Slotted object interface

fix-squashed-planets
immibis 2021-07-04 16:39:49 +02:00
parent fabbdda964
commit 76314f522f
34 changed files with 725 additions and 665 deletions

View File

@ -377,7 +377,6 @@ set(BASE_SOURCES
object/implementation/programmable_impl.h object/implementation/programmable_impl.h
object/implementation/task_executor_impl.cpp object/implementation/task_executor_impl.cpp
object/implementation/task_executor_impl.h object/implementation/task_executor_impl.h
object/interface/carrier_object.h
object/interface/controllable_object.h object/interface/controllable_object.h
object/interface/damageable_object.h object/interface/damageable_object.h
object/interface/destroyable_object.h object/interface/destroyable_object.h
@ -388,12 +387,12 @@ set(BASE_SOURCES
object/interface/jostleable_object.h object/interface/jostleable_object.h
object/interface/movable_object.h object/interface/movable_object.h
object/interface/power_container_object.h object/interface/power_container_object.h
object/interface/powered_object.h
object/interface/program_storage_object.h object/interface/program_storage_object.h
object/interface/programmable_object.h object/interface/programmable_object.h
object/interface/ranged_object.h object/interface/ranged_object.h
object/interface/shielded_auto_regen_object.h object/interface/shielded_auto_regen_object.h
object/interface/shielded_object.h object/interface/shielded_object.h
object/interface/slotted_object.h
object/interface/task_executor_object.h object/interface/task_executor_object.h
object/interface/trace_drawing_object.cpp object/interface/trace_drawing_object.cpp
object/interface/trace_drawing_object.h object/interface/trace_drawing_object.h

View File

@ -37,10 +37,9 @@
#include "object/object.h" #include "object/object.h"
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/interface/carrier_object.h"
#include "object/interface/controllable_object.h" #include "object/interface/controllable_object.h"
#include "object/interface/movable_object.h" #include "object/interface/movable_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "physics/physics.h" #include "physics/physics.h"
@ -57,18 +56,15 @@ static void SetTransparency(CObject* obj, float value)
{ {
obj->SetTransparency(value); obj->SetTransparency(value);
if (obj->Implements(ObjectInterfaceType::Carrier)) if (obj->Implements(ObjectInterfaceType::Slotted))
{ {
CObject* cargo = dynamic_cast<CCarrierObject&>(*obj).GetCargo(); CSlottedObject *slotted = dynamic_cast<CSlottedObject*>(obj);
if (cargo != nullptr) for(int slot = slotted->GetNumSlots()-1; slot >= 0; slot--)
cargo->SetTransparency(value); {
} CObject *contained = slotted->GetSlotContainedObject(slot);
if (contained != nullptr)
if (obj->Implements(ObjectInterfaceType::Powered)) SetTransparency(contained, value);
{ }
CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power != nullptr)
power->SetTransparency(value);
} }
} }

View File

@ -35,6 +35,8 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/slotted_object.h"
#include "object/motion/motionhuman.h" #include "object/motion/motionhuman.h"
#include "object/subclass/shielder.h" #include "object/subclass/shielder.h"
@ -127,9 +129,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
// Seeking the position of the battery. // Seeking the position of the battery.
CObject* power = nullptr; CObject* power = GetObjectInPowerCellSlot(obj);
if (obj->Implements(ObjectInterfaceType::Powered))
power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power == nullptr) if (power == nullptr)
{ {
@ -1385,25 +1385,16 @@ void CPyro::DeleteObject(bool primary, bool secondary)
type != OBJECT_NUCLEAR && type != OBJECT_NUCLEAR &&
type != OBJECT_ENERGY ) type != OBJECT_ENERGY )
{ {
if (m_object->Implements(ObjectInterfaceType::Powered)) if (m_object->Implements(ObjectInterfaceType::Slotted))
{ {
CPoweredObject* poweredObject = dynamic_cast<CPoweredObject*>(m_object); CSlottedObject* asSlotted = dynamic_cast<CSlottedObject*>(m_object);
CObject* sub = poweredObject->GetPower(); for (int slot = asSlotted->GetNumSlots() - 1; slot >= 0; slot--)
if (sub != nullptr)
{ {
CObjectManager::GetInstancePointer()->DeleteObject(sub); if (CObject* sub = asSlotted->GetSlotContainedObject(slot))
poweredObject->SetPower(nullptr); {
} CObjectManager::GetInstancePointer()->DeleteObject(sub);
} asSlotted->SetSlotContainedObject(slot, nullptr);
}
if (m_object->Implements(ObjectInterfaceType::Carrier))
{
CCarrierObject* carrierObject = dynamic_cast<CCarrierObject*>(m_object);
CObject* sub = carrierObject->GetCargo();
if (sub != nullptr)
{
CObjectManager::GetInstancePointer()->DeleteObject(sub);
carrierObject->SetCargo(nullptr);
} }
} }
} }
@ -1416,18 +1407,15 @@ void CPyro::DeleteObject(bool primary, bool secondary)
CObject* transporter = dynamic_cast<CTransportableObject&>(*m_object).GetTransporter(); CObject* transporter = dynamic_cast<CTransportableObject&>(*m_object).GetTransporter();
if (transporter != nullptr) if (transporter != nullptr)
{ {
if (transporter->Implements(ObjectInterfaceType::Powered)) assert(transporter->Implements(ObjectInterfaceType::Slotted));
CSlottedObject* asSlotted = dynamic_cast<CSlottedObject*>(transporter);
for (int slotNum = asSlotted->GetNumSlots() - 1; slotNum >= 0; slotNum--)
{ {
CPoweredObject* powered = dynamic_cast<CPoweredObject*>(transporter); if (asSlotted->GetSlotContainedObject(slotNum) == m_object)
if (powered->GetPower() == m_object) {
powered->SetPower(nullptr); asSlotted->SetSlotContainedObject(slotNum, nullptr);
} break;
}
if (transporter->Implements(ObjectInterfaceType::Carrier))
{
CCarrierObject* carrier = dynamic_cast<CCarrierObject*>(transporter);
if (carrier->GetCargo() == m_object)
carrier->SetCargo(nullptr);
} }
} }
} }
@ -2196,11 +2184,10 @@ void CPyro::BurnProgress()
oldObj->SetPartRotation(m_burnPart[i].part, pos); oldObj->SetPartRotation(m_burnPart[i].part, pos);
} }
if (m_object->Implements(ObjectInterfaceType::Powered)) // TODO: should this apply to every slot?
if (CObject* sub = GetObjectInPowerCellSlot(m_object)) // is there a battery?
{ {
CObject* sub = dynamic_cast<CPoweredObject&>(*m_object).GetPower(); sub->SetScaleY(1.0f - m_progress); // complete flattening
if (sub != nullptr) // is there a battery?
sub->SetScaleY(1.0f - m_progress); // complete flattening
} }
} }

View File

@ -69,6 +69,8 @@
#include "object/auto/auto.h" #include "object/auto/auto.h"
#include "object/interface/slotted_object.h"
#include "object/motion/motion.h" #include "object/motion/motion.h"
#include "object/motion/motionhuman.h" #include "object/motion/motionhuman.h"
#include "object/motion/motiontoto.h" #include "object/motion/motiontoto.h"
@ -1392,12 +1394,8 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
CObject* object = GetSelect(); CObject* object = GetSelect();
if (object != nullptr) if (object != nullptr)
{ {
if (object->Implements(ObjectInterfaceType::Powered)) if (CPowerContainerObject *power = GetObjectPowerCell(object))
{ power->SetEnergyLevel(1.0f);
CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
}
if (object->Implements(ObjectInterfaceType::Shielded)) if (object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f); dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f);
@ -1414,12 +1412,8 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (object != nullptr) if (object != nullptr)
{ {
if (object->Implements(ObjectInterfaceType::Powered)) if (CPowerContainerObject *power = GetObjectPowerCell(object))
{ power->SetEnergyLevel(1.0f);
CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
}
} }
return; return;
} }
@ -2007,21 +2001,12 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
if (obj->GetProxyActivate()) continue; if (obj->GetProxyActivate()) continue;
CObject* target = obj; CObject* target = obj;
// TODO: should this also apply to slots other than power cell slots?
if (obj->Implements(ObjectInterfaceType::PowerContainer) && obj->Implements(ObjectInterfaceType::Transportable)) if (obj->Implements(ObjectInterfaceType::PowerContainer) && obj->Implements(ObjectInterfaceType::Transportable))
{ {
target = dynamic_cast<CTransportableObject&>(*obj).GetTransporter(); // battery connected CObject *transporter = dynamic_cast<CTransportableObject&>(*obj).GetTransporter(); // battery connected
if (target == nullptr) if (transporter != nullptr && obj == GetObjectInPowerCellSlot(transporter))
{ target = transporter;
target = obj; // standalone battery
}
else
{
if (!target->Implements(ObjectInterfaceType::Powered) || dynamic_cast<CPoweredObject&>(*target).GetPower() != obj)
{
// transported, but not in the power slot
target = obj;
}
}
} }
if (!obj->Implements(ObjectInterfaceType::Old)) continue; if (!obj->Implements(ObjectInterfaceType::Old)) continue;
@ -4716,29 +4701,26 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (IsObjectBeingTransported(obj)) continue; if (IsObjectBeingTransported(obj)) continue;
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*obj).IsDying()) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*obj).IsDying()) continue;
if (obj->Implements(ObjectInterfaceType::Carrier)) if (obj->Implements(ObjectInterfaceType::Slotted))
{ {
CObject* cargo = dynamic_cast<CCarrierObject&>(*obj).GetCargo(); CSlottedObject* slotted = dynamic_cast<CSlottedObject*>(obj);
if (cargo != nullptr) // object transported? for (int slot = slotted->GetNumSlots() - 1; slot >= 0; slot--)
{ {
line = MakeUnique<CLevelParserLine>("CreateFret"); if (CObject *sub = slotted->GetSlotContainedObject(slot))
IOWriteObject(line.get(), cargo, dirname, objRank++); {
levelParser.AddLine(std::move(line)); if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER))
line = MakeUnique<CLevelParserLine>("CreatePower");
else if (slot == slotted->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING))
line = MakeUnique<CLevelParserLine>("CreateFret");
else
line = MakeUnique<CLevelParserLine>("CreateSlotObject");
line->AddParam("slotNum", MakeUnique<CLevelParserParam>(slot));
IOWriteObject(line.get(), sub, dirname, objRank++);
levelParser.AddLine(std::move(line));
}
} }
} }
if (obj->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power != nullptr) // battery transported?
{
line = MakeUnique<CLevelParserLine>("CreatePower");
IOWriteObject(line.get(), power, dirname, objRank++);
levelParser.AddLine(std::move(line));
}
}
line = MakeUnique<CLevelParserLine>("CreateObject"); line = MakeUnique<CLevelParserLine>("CreateObject");
IOWriteObject(line.get(), obj, dirname, objRank++); IOWriteObject(line.get(), obj, dirname, objRank++);
levelParser.AddLine(std::move(line)); levelParser.AddLine(std::move(line));
@ -4867,7 +4849,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
CLevelParser levelParser(filename); CLevelParser levelParser(filename);
levelParser.SetLevelPaths(m_levelCategory, m_levelChap, m_levelRank); levelParser.SetLevelPaths(m_levelCategory, m_levelChap, m_levelRank);
levelParser.Load(); levelParser.Load();
int numObjects = levelParser.CountLines("CreateObject") + levelParser.CountLines("CreatePower") + levelParser.CountLines("CreateFret"); int numObjects = levelParser.CountLines("CreateObject") + levelParser.CountLines("CreatePower") + levelParser.CountLines("CreateFret") + levelParser.CountLines("CreateSlotObject");
m_base = nullptr; m_base = nullptr;
@ -4876,6 +4858,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
CObject* sel = nullptr; CObject* sel = nullptr;
int objRank = 0; int objRank = 0;
int objCounter = 0; int objCounter = 0;
std::map<int, CObject*> slots;
for (auto& line : levelParser.GetLines()) for (auto& line : levelParser.GetLines())
{ {
if (line->GetCommand() == "Mission") if (line->GetCommand() == "Mission")
@ -4908,6 +4891,16 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
objCounter++; objCounter++;
} }
if (line->GetCommand() == "CreateSlotObject")
{
int slotNum = line->GetParam("slotNum")->AsInt();
CObject *slotObject = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects));
objCounter++;
assert(slots.find(slotNum) == slots.end());
slots.emplace(slotNum, slotObject);
}
if (line->GetCommand() == "CreateObject") if (line->GetCommand() == "CreateObject")
{ {
CObject* obj = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), objRank++); CObject* obj = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), objRank++);
@ -4915,20 +4908,50 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
if (line->GetParam("select")->AsBool(false)) if (line->GetParam("select")->AsBool(false))
sel = obj; sel = obj;
if (cargo != nullptr) if (obj->Implements(ObjectInterfaceType::Slotted))
{ {
assert(obj->Implements(ObjectInterfaceType::Carrier)); // TODO: exception? CSlottedObject* asSlotted = dynamic_cast<CSlottedObject*>(obj);
assert(obj->Implements(ObjectInterfaceType::Old)); if (cargo != nullptr)
dynamic_cast<CCarrierObject&>(*obj).SetCargo(cargo); {
auto task = MakeUnique<CTaskManip>(dynamic_cast<COldObject*>(obj)); int slotNum = asSlotted->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING);
task->Start(TMO_AUTO, TMA_GRAB); // holds the object! assert(slotNum >= 0);
assert(slots.find(slotNum) == slots.end());
asSlotted->SetSlotContainedObject(slotNum, cargo);
// TODO: eww!
assert(obj->Implements(ObjectInterfaceType::Old));
auto task = MakeUnique<CTaskManip>(dynamic_cast<COldObject*>(obj));
task->Start(TMO_AUTO, TMA_GRAB); // holds the object!
}
if (power != nullptr)
{
int slotNum = asSlotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER);
assert(slotNum >= 0);
assert(slots.find(slotNum) == slots.end());
asSlotted->SetSlotContainedObject(slotNum, power);
}
for (std::pair<const int, CObject*>& slot : slots)
{
asSlotted->SetSlotContainedObject(slot.first, slot.second);
}
cargo = nullptr;
power = nullptr;
slots.clear();
}
else
{
// TODO: exception?
assert(slots.empty());
assert(power == nullptr);
assert(cargo == nullptr);
} }
if (power != nullptr) if (power != nullptr)
{ {
assert(obj->Implements(ObjectInterfaceType::Powered)); dynamic_cast<CSlottedObject&>(*obj).SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER, power);
dynamic_cast<CPoweredObject&>(*obj).SetPower(power);
assert(power->Implements(ObjectInterfaceType::Transportable));
dynamic_cast<CTransportableObject&>(*power).SetTransporter(obj); dynamic_cast<CTransportableObject&>(*power).SetTransporter(obj);
} }
cargo = nullptr; cargo = nullptr;
@ -4938,6 +4961,11 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
} }
} }
// all slot objects assigned to parent objects
assert(slots.empty());
assert(power == nullptr);
assert(cargo == nullptr);
m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE); m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE);
// Reads the file of stacks of execution. // Reads the file of stacks of execution.

View File

@ -26,7 +26,8 @@
#include "object/object.h" #include "object/object.h"
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/interface/powered_object.h" #include "object/interface/power_container_object.h"
#include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include <limits> #include <limits>
@ -80,13 +81,9 @@ bool CObjectCondition::CheckForObject(CObject* obj)
{ {
power = dynamic_cast<CPowerContainerObject*>(obj); power = dynamic_cast<CPowerContainerObject*>(obj);
} }
else if (obj->Implements(ObjectInterfaceType::Powered)) else
{ {
CObject* powerObj = dynamic_cast<CPoweredObject&>(*obj).GetPower(); power = GetObjectPowerCell(obj);
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{
power = dynamic_cast<CPowerContainerObject*>(powerObj);
}
} }
if (power != nullptr) if (power != nullptr)

View File

@ -32,7 +32,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -59,7 +59,7 @@ CAutoLabo::CAutoLabo(COldObject* object) : CAuto(object)
m_soundChannel = -1; m_soundChannel = -1;
Init(); Init();
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -131,7 +131,7 @@ Error CAutoLabo::StartAction(int param)
return ERR_LABO_ALREADY; return ERR_LABO_ALREADY;
} }
CObject* power = m_object->GetPower(); CObject* power = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObject(0);
if (power == nullptr) if (power == nullptr)
{ {
return ERR_LABO_NULL; return ERR_LABO_NULL;
@ -308,7 +308,7 @@ bool CAutoLabo::EventProcess(const Event &event)
{ {
if ( m_progress < 1.0f ) if ( m_progress < 1.0f )
{ {
power = m_object->GetPower(); power = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObject(0);
if ( power != nullptr ) if ( power != nullptr )
{ {
power->SetScale(1.0f-m_progress); power->SetScale(1.0f-m_progress);
@ -366,10 +366,10 @@ bool CAutoLabo::EventProcess(const Event &event)
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
UpdateInterface(); UpdateInterface();
power = m_object->GetPower(); power = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObject(0);
if ( power != nullptr ) if ( power != nullptr )
{ {
m_object->SetPower(nullptr); dynamic_cast<CSlottedObject&>(*m_object).SetSlotContainedObject(0, nullptr);
CObjectManager::GetInstancePointer()->DeleteObject(power); CObjectManager::GetInstancePointer()->DeleteObject(power);
} }
@ -457,7 +457,7 @@ Error CAutoLabo::GetError()
return ERR_BAT_VIRUS; return ERR_BAT_VIRUS;
} }
CObject* obj = m_object->GetPower(); CObject* obj = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObject(0);
if (obj == nullptr) return ERR_LABO_NULL; if (obj == nullptr) return ERR_LABO_NULL;
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();
if ( type != OBJECT_BULLET && type != OBJECT_TNT ) return ERR_LABO_BAD; if ( type != OBJECT_BULLET && type != OBJECT_TNT ) return ERR_LABO_BAD;

View File

@ -32,7 +32,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -53,7 +53,7 @@ CAutoNuclearPlant::CAutoNuclearPlant(COldObject* object) : CAuto(object)
m_channelSound = -1; m_channelSound = -1;
Init(); Init();
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -239,7 +239,7 @@ bool CAutoNuclearPlant::EventProcess(const Event &event)
if ( cargo != nullptr ) if ( cargo != nullptr )
{ {
CObjectManager::GetInstancePointer()->DeleteObject(cargo); CObjectManager::GetInstancePointer()->DeleteObject(cargo);
m_object->SetPower(nullptr); m_object->SetSlotContainedObject(0, nullptr);
} }
CreatePower(); // creates the atomic cell CreatePower(); // creates the atomic cell
@ -327,7 +327,7 @@ bool CAutoNuclearPlant::CreateInterface(bool bSelect)
CObject* CAutoNuclearPlant::SearchUranium() CObject* CAutoNuclearPlant::SearchUranium()
{ {
CObject* obj = m_object->GetPower(); CObject* obj = m_object->GetSlotContainedObject(0);
if (obj == nullptr) return nullptr; if (obj == nullptr) return nullptr;
if (obj->GetType() == OBJECT_URANIUM) return obj; if (obj->GetType() == OBJECT_URANIUM) return obj;
return nullptr; return nullptr;
@ -402,7 +402,7 @@ void CAutoNuclearPlant::CreatePower()
dynamic_cast<CTransportableObject&>(*power).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*power).SetTransporter(m_object);
power->SetPosition(Math::Vector(22.0f, 3.0f, 0.0f)); power->SetPosition(Math::Vector(22.0f, 3.0f, 0.0f));
m_object->SetPower(power); m_object->SetSlotContainedObject(0, power);
} }
@ -422,7 +422,7 @@ Error CAutoNuclearPlant::GetError()
//? if ( m_object->GetEnergy() < ENERGY_POWER ) return ERR_NUCLEAR_LOW; //? if ( m_object->GetEnergy() < ENERGY_POWER ) return ERR_NUCLEAR_LOW;
CObject* obj = m_object->GetPower(); CObject* obj = m_object->GetSlotContainedObject(0);
if ( obj == nullptr ) return ERR_NUCLEAR_EMPTY; if ( obj == nullptr ) return ERR_NUCLEAR_EMPTY;
if ( obj->GetLock() ) return ERR_OK; if ( obj->GetLock() ) return ERR_OK;
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();

View File

@ -30,8 +30,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -267,34 +266,22 @@ void CAutoPowerCaptor::ChargeObject(float rTime)
} }
} }
if (obj->Implements(ObjectInterfaceType::Powered)) if (obj->Implements(ObjectInterfaceType::Slotted))
{ {
CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower(); CSlottedObject* slotted = dynamic_cast<CSlottedObject*>(obj);
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) for (int slot = slotted->GetNumSlots(); slot >= 0; slot--)
{ {
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power); CObject *held = slotted->GetSlotContainedObject(slot);
if (powerContainer->IsRechargeable()) if (held != nullptr && held->Implements(ObjectInterfaceType::PowerContainer))
{ {
float energy = powerContainer->GetEnergy(); CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(held);
energy += rTime/2.0f; if (powerContainer->IsRechargeable())
if ( energy > 1.0f ) energy = 1.0f; {
powerContainer->SetEnergy(energy); float energy = powerContainer->GetEnergy();
} energy += rTime/2.0f;
} if ( energy > 1.0f ) energy = 1.0f;
} powerContainer->SetEnergy(energy);
}
if (obj->Implements(ObjectInterfaceType::Carrier))
{
CObject* power = dynamic_cast<CCarrierObject&>(*obj).GetCargo();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
if (powerContainer->IsRechargeable())
{
float energy = powerContainer->GetEnergy();
energy += rTime/2.0f;
if ( energy > 1.0f ) energy = 1.0f;
powerContainer->SetEnergy(energy);
} }
} }
} }

View File

@ -34,7 +34,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -57,7 +57,7 @@ CAutoPowerPlant::CAutoPowerPlant(COldObject* object) : CAuto(object)
m_partiSphere = -1; m_partiSphere = -1;
Init(); Init();
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -79,17 +79,18 @@ void CAutoPowerPlant::DeleteObject(bool all)
if ( !all ) if ( !all )
{ {
// TODO: why are we only searching for titanium and power cells? why don't we delete any object regardless of type?
CObject* cargo = SearchMetal(); CObject* cargo = SearchMetal();
if ( cargo != nullptr ) if ( cargo != nullptr )
{ {
m_object->SetPower(nullptr); m_object->SetSlotContainedObject(0, nullptr);
CObjectManager::GetInstancePointer()->DeleteObject(cargo); CObjectManager::GetInstancePointer()->DeleteObject(cargo);
} }
cargo = SearchPower(); cargo = SearchPower();
if ( cargo != nullptr ) if ( cargo != nullptr )
{ {
m_object->SetPower(nullptr); m_object->SetSlotContainedObject(0, nullptr);
CObjectManager::GetInstancePointer()->DeleteObject(cargo); CObjectManager::GetInstancePointer()->DeleteObject(cargo);
} }
} }
@ -320,7 +321,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event)
cargo = SearchMetal(); cargo = SearchMetal();
if ( cargo != nullptr ) if ( cargo != nullptr )
{ {
m_object->SetPower(nullptr); m_object->SetSlotContainedObject(0, nullptr);
CObjectManager::GetInstancePointer()->DeleteObject(cargo); CObjectManager::GetInstancePointer()->DeleteObject(cargo);
} }
@ -333,7 +334,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event)
cargo->SetLock(false); // usable battery cargo->SetLock(false); // usable battery
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
cargo->SetPosition(Math::Vector(0.0f, 3.0f, 0.0f)); cargo->SetPosition(Math::Vector(0.0f, 3.0f, 0.0f));
m_object->SetPower(cargo); m_object->SetSlotContainedObject(0, cargo);
m_main->DisplayError(INFO_ENERGY, m_object); m_main->DisplayError(INFO_ENERGY, m_object);
} }
@ -387,7 +388,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event)
CObject* CAutoPowerPlant::SearchMetal() CObject* CAutoPowerPlant::SearchMetal()
{ {
CObject* obj = m_object->GetPower(); CObject* obj = m_object->GetSlotContainedObject(0);
if ( obj == nullptr ) return nullptr; if ( obj == nullptr ) return nullptr;
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();
@ -512,7 +513,7 @@ Error CAutoPowerPlant::GetError()
if ( m_object->GetEnergy() < POWERPLANT_POWER ) return ERR_ENERGY_LOW; if ( m_object->GetEnergy() < POWERPLANT_POWER ) return ERR_ENERGY_LOW;
CObject* obj = m_object->GetPower(); CObject* obj = m_object->GetSlotContainedObject(0);
if (obj == nullptr) return ERR_ENERGY_EMPTY; if (obj == nullptr) return ERR_ENERGY_EMPTY;
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();
if ( type == OBJECT_POWER ) return ERR_OK; if ( type == OBJECT_POWER ) return ERR_OK;

View File

@ -28,9 +28,6 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h"
#include "object/interface/powered_object.h"
#include "sound/sound.h" #include "sound/sound.h"
#include "ui/controls/gauge.h" #include "ui/controls/gauge.h"
@ -134,32 +131,13 @@ bool CAutoPowerStation::EventProcess(const Event &event)
if (big > 0.0f) if (big > 0.0f)
{ {
CObject* vehicle = SearchVehicle(); CObject* vehicle = SearchVehicle();
if (vehicle != nullptr) if (vehicle != nullptr && vehicle->Implements(ObjectInterfaceType::Slotted))
{ {
if (vehicle->Implements(ObjectInterfaceType::Powered)) CSlottedObject* slotted = dynamic_cast<CSlottedObject*>(vehicle);
for (int slot = slotted->GetNumSlots(); slot >= 0; slot--)
{ {
CObject* power = dynamic_cast<CPoweredObject&>(*vehicle).GetPower(); CObject *power = slotted->GetSlotContainedObject(slot);
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
if (powerContainer->IsRechargeable())
{
float energy = powerContainer->GetEnergy();
float add = event.rTime*0.2f;
if ( add > big*4.0f ) add = big*4.0f;
if ( add > 1.0f-energy ) add = 1.0f-energy;
energy += add; // Charging the battery
powerContainer->SetEnergy(energy);
if ( energy < freq ) freq = energy;
big -= add/4.0f; // discharge the large battery
}
}
}
if (vehicle->Implements(ObjectInterfaceType::Carrier))
{
CObject* power = dynamic_cast<CCarrierObject&>(*vehicle).GetCargo();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{ {
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power); CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
if (powerContainer->IsRechargeable()) if (powerContainer->IsRechargeable())

View File

@ -32,7 +32,7 @@
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -57,7 +57,7 @@ CAutoResearch::CAutoResearch(COldObject* object) : CAuto(object)
Init(); Init();
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -114,11 +114,11 @@ Error CAutoResearch::StartAction(int param)
return ERR_RESEARCH_ALREADY; return ERR_RESEARCH_ALREADY;
} }
if (m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer)) if (m_object->GetSlotContainedObject(0) == nullptr || !m_object->GetSlotContainedObject(0)->Implements(ObjectInterfaceType::PowerContainer))
{ {
return ERR_RESEARCH_POWER; return ERR_RESEARCH_POWER;
} }
CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower()); CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(m_object->GetSlotContainedObject(0));
if ( power->GetCapacity() > 1.0f ) if ( power->GetCapacity() > 1.0f )
{ {
return ERR_RESEARCH_TYPE; return ERR_RESEARCH_TYPE;
@ -222,7 +222,9 @@ bool CAutoResearch::EventProcess(const Event &event)
FireStopUpdate(m_progress, true); // flashes FireStopUpdate(m_progress, true); // flashes
if ( m_progress < 1.0f ) if ( m_progress < 1.0f )
{ {
if ( m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer) ) // more battery? CObject* batteryObj = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObject(0);
if ( batteryObj == nullptr || !batteryObj->Implements(ObjectInterfaceType::PowerContainer) ) // more battery?
{ {
SetBusy(false); SetBusy(false);
UpdateInterface(); UpdateInterface();
@ -232,7 +234,7 @@ bool CAutoResearch::EventProcess(const Event &event)
m_speed = 1.0f/1.0f; m_speed = 1.0f/1.0f;
return true; return true;
} }
power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower()); power = dynamic_cast<CPowerContainerObject*>(batteryObj);
power->SetEnergyLevel(1.0f-m_progress); power->SetEnergyLevel(1.0f-m_progress);
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time ) if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
@ -302,11 +304,11 @@ Error CAutoResearch::GetError()
return ERR_BAT_VIRUS; return ERR_BAT_VIRUS;
} }
if (m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer)) if (m_object->GetSlotContainedObject(0) == nullptr || !m_object->GetSlotContainedObject(0)->Implements(ObjectInterfaceType::PowerContainer))
{ {
return ERR_RESEARCH_POWER; return ERR_RESEARCH_POWER;
} }
CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower()); CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(m_object->GetSlotContainedObject(0));
if ( power->GetCapacity() > 1.0f ) if ( power->GetCapacity() > 1.0f )
{ {
return ERR_RESEARCH_TYPE; return ERR_RESEARCH_TYPE;

View File

@ -32,7 +32,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "physics/physics.h" #include "physics/physics.h"
@ -61,7 +61,7 @@ CAutoTower::CAutoTower(COldObject* object) : CAuto(object)
m_time = 0.0f; m_time = 0.0f;
m_lastUpdateTime = 0.0f; m_lastUpdateTime = 0.0f;
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -125,13 +125,8 @@ bool CAutoTower::EventProcess(const Event &event)
return true; return true;
} }
CPowerContainerObject* power = nullptr; CPowerContainerObject* power = GetObjectPowerCell(m_object);
float energy = 0.0f; float energy = power == nullptr ? 0.0f : power->GetEnergy();
if ( m_object->GetPower() != nullptr && m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer) )
{
power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower());
energy = power->GetEnergy();
}
UpdateInterface(event.rTime); UpdateInterface(event.rTime);
@ -321,12 +316,13 @@ Error CAutoTower::GetError()
return ERR_BAT_VIRUS; return ERR_BAT_VIRUS;
} }
if ( m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer) ) CPowerContainerObject *power = GetObjectPowerCell(m_object);
if ( power == nullptr )
{ {
return ERR_TOWER_POWER; // no battery return ERR_TOWER_POWER; // no battery
} }
if ( dynamic_cast<CPowerContainerObject&>(*m_object->GetPower()).GetEnergy() < ENERGY_FIRE ) if ( power->GetEnergy() < ENERGY_FIRE )
{ {
return ERR_TOWER_ENERGY; // not enough energy return ERR_TOWER_ENERGY; // not enough energy
} }

View File

@ -1,55 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "object/object.h"
#include "object/object_interface_type.h"
/**
* \class CCarrierObject
* \brief Interface for carrier objects
*/
class CCarrierObject
{
public:
explicit CCarrierObject(ObjectInterfaceTypes& types)
{
types[static_cast<int>(ObjectInterfaceType::Carrier)] = true;
}
virtual ~CCarrierObject()
{}
//! Returns carried object
virtual CObject* GetCargo() = 0;
//! Sets carried object
virtual void SetCargo(CObject* cargo) = 0;
//! Checks whether there is any cargo
inline bool IsCarryingCargo()
{
return GetCargo() != nullptr;
}
};
inline bool IsObjectCarryingCargo(CObject* obj)
{
return obj->Implements(ObjectInterfaceType::Carrier) &&
dynamic_cast<CCarrierObject&>(*obj).IsCarryingCargo();
}

View File

@ -1,94 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "object/object.h"
#include "object/object_interface_type.h"
#include "object/interface/power_container_object.h"
class CObject;
/**
* \class CPoweredObject
* \brief Interface for objects powered using power cells
*
* TODO: It currently includes objects that take other objects as input
* and convert them, for example PowerPlant.
* We should create a dedicated interface for such uses.
*/
class CPoweredObject
{
public:
explicit CPoweredObject(ObjectInterfaceTypes& types)
{
types[static_cast<int>(ObjectInterfaceType::Powered)] = true;
}
virtual ~CPoweredObject()
{}
//! Returns the power cell
virtual CObject* GetPower() = 0;
//! Sets power cell
virtual void SetPower(CObject* power) = 0;
//! Returns the relative position of power cell
virtual Math::Vector GetPowerPosition() = 0;
//! Sets the relative position of power cell
virtual void SetPowerPosition(const Math::Vector& powerPosition) = 0;
};
inline float GetObjectEnergy(CObject* object)
{
float energy = 0.0f;
if (object->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
{
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
}
}
return energy;
}
inline float GetObjectEnergyLevel(CObject* object)
{
float energy = 0.0f;
if (object->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
{
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergyLevel();
}
}
return energy;
}
inline bool ObjectHasPowerCell(CObject* object)
{
return object->Implements(ObjectInterfaceType::Powered) &&
dynamic_cast<CPoweredObject&>(*object).GetPower() != nullptr;
}

View File

@ -0,0 +1,148 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "math/vector.h"
#include "object/object.h"
#include "object/object_interface_type.h"
#include "object/interface/power_container_object.h"
#include <assert.h>
class CObject;
/**
* \class CSlottedObject
* \brief Interface for objects that hold other objects
*/
class CSlottedObject
{
public:
///! Object-independent identifiers for certain special slots
enum class Pseudoslot
{
POWER,
CARRYING
};
explicit CSlottedObject(ObjectInterfaceTypes& types)
{
types[static_cast<int>(ObjectInterfaceType::Slotted)] = true;
}
virtual ~CSlottedObject()
{}
//! Given one of the PSEUDOSLOT enums, returns real slot number, or -1 if specified pseudoslot is not present in this object.
virtual int MapPseudoSlot(Pseudoslot pseudoslot) = 0;
//! Get number of slots. Valid slot numbers are 0 up to GetNumSlots()-1. Using invalid slot numbers in the other functions will crash the game.
virtual int GetNumSlots() = 0;
//! Get relative position of a slot.
virtual Math::Vector GetSlotPosition(int slotNum) = 0;
//! Get relative angle (in radians) where robot should be positioned when inserting into a slot.
virtual float GetSlotAngle(int slotNum) = 0;
//! Get the maximum angular distance from the ideal angle (in radians) where robot should be positioned when inserting into a slot.
virtual float GetSlotAcceptanceAngle(int slotNum) = 0;
//! Get object contained in a slot.
virtual CObject *GetSlotContainedObject(int slotNum) = 0;
//! Set object contained in a slot.
virtual void SetSlotContainedObject(int slotNum, CObject *object) = 0;
void SetSlotContainedObjectReq(Pseudoslot pseudoslot, CObject *object)
{
int slotNum = MapPseudoSlot(pseudoslot);
assert(slotNum >= 0);
SetSlotContainedObject(slotNum, object);
}
CObject *GetSlotContainedObjectOpt(Pseudoslot pseudoslot)
{
int slotNum = MapPseudoSlot(pseudoslot);
return slotNum < 0 ? nullptr : GetSlotContainedObject(slotNum);
}
CObject *GetSlotContainedObjectReq(Pseudoslot pseudoslot)
{
int slotNum = MapPseudoSlot(pseudoslot);
assert(slotNum >= 0);
return GetSlotContainedObject(slotNum);
}
};
inline bool HasPowerCellSlot(CObject *object)
{
if (object->Implements(ObjectInterfaceType::Slotted))
{
return dynamic_cast<CSlottedObject&>(*object).MapPseudoSlot(CSlottedObject::Pseudoslot::POWER) >= 0;
}
return false;
}
inline CObject *GetObjectInPowerCellSlot(CObject *object)
{
if (object->Implements(ObjectInterfaceType::Slotted))
{
return dynamic_cast<CSlottedObject&>(*object).GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::POWER);
}
return nullptr;
}
inline CPowerContainerObject *GetObjectPowerCell(CObject *object)
{
if (CObject *powerSlotObj = GetObjectInPowerCellSlot(object))
{
if (powerSlotObj->Implements(ObjectInterfaceType::PowerContainer))
{
return dynamic_cast<CPowerContainerObject*>(powerSlotObj);
}
}
return nullptr;
}
inline float GetObjectEnergy(CObject* object)
{
if (CPowerContainerObject* power = GetObjectPowerCell(object))
return power->GetEnergy();
return 0.0f;
}
inline float GetObjectEnergyLevel(CObject* object)
{
if (CPowerContainerObject* power = GetObjectPowerCell(object))
return power->GetEnergyLevel();
return 0.0f;
}
inline bool ObjectHasPowerCell(CObject* object)
{
// XXX: not GetObjectPowerCell? We count e.g. titanium cubes as power cells in this function?
return GetObjectInPowerCellSlot(object) != nullptr;
}
inline bool IsObjectCarryingCargo(CObject* object)
{
if (object->Implements(ObjectInterfaceType::Slotted))
{
return dynamic_cast<CSlottedObject&>(*object).GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::CARRYING) != nullptr;
}
return false;
}

View File

@ -33,8 +33,6 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h"
#include "physics/physics.h" #include "physics/physics.h"
#include "sound/sound.h" #include "sound/sound.h"

View File

@ -33,8 +33,8 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/programmable_object.h" #include "object/interface/programmable_object.h"
#include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "physics/physics.h" #include "physics/physics.h"
@ -1061,7 +1061,8 @@ void CMotionVehicle::Create(Math::Vector pos, float angle, ObjectType type,
type != OBJECT_APOLLO2) type != OBJECT_APOLLO2)
{ {
CObject* powerCell = nullptr; CObject* powerCell = nullptr;
Math::Vector powerCellPos = m_object->GetPowerPosition(); int powerSlotIndex = m_object->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER);
Math::Vector powerCellPos = m_object->GetSlotPosition(powerSlotIndex);
float powerCellAngle = 0.0f; float powerCellAngle = 0.0f;
if (power <= 1.0f) if (power <= 1.0f)
{ {
@ -1076,8 +1077,7 @@ void CMotionVehicle::Create(Math::Vector pos, float angle, ObjectType type,
powerCell->SetPosition(powerCellPos); powerCell->SetPosition(powerCellPos);
powerCell->SetRotation(Math::Vector(0.0f, powerCellAngle, 0.0f)); powerCell->SetRotation(Math::Vector(0.0f, powerCellAngle, 0.0f));
dynamic_cast<CTransportableObject&>(*powerCell).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*powerCell).SetTransporter(m_object);
assert(m_object->Implements(ObjectInterfaceType::Powered)); m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER, powerCell);
m_object->SetPower(powerCell);
} }
pos = m_object->GetPosition(); pos = m_object->GetPosition();

View File

@ -39,8 +39,6 @@ enum class ObjectInterfaceType
Programmable, //!< objects that can be programmed in CBOT Programmable, //!< objects that can be programmed in CBOT
TaskExecutor, //!< objects that can execute tasks (CTask classes) TaskExecutor, //!< objects that can execute tasks (CTask classes)
Jostleable, //!< object that can be jostled Jostleable, //!< object that can be jostled
Carrier, //!< object that can carry other objects
Powered, //!< object powered with power cell
Movable, //!< objects that can move Movable, //!< objects that can move
Flying, //!< objects that can fly Flying, //!< objects that can fly
JetFlying, //!< objects that can fly using a jet engine JetFlying, //!< objects that can fly using a jet engine
@ -54,6 +52,7 @@ enum class ObjectInterfaceType
Shielded, //!< objects that can be destroyed after the shield goes down to 0 Shielded, //!< objects that can be destroyed after the shield goes down to 0
ShieldedAutoRegen, //!< shielded objects with auto shield regeneration ShieldedAutoRegen, //!< shielded objects with auto shield regeneration
Old, //!< old objects, TODO: remove once no longer necessary Old, //!< old objects, TODO: remove once no longer necessary
Slotted, //!< objects that can carry other objects (in their gripper, power cell slot, or other slots)
Max //!< maximum value (for getting number of items in enum) Max //!< maximum value (for getting number of items in enum)
}; };

View File

@ -81,8 +81,7 @@ COldObject::COldObject(int id)
CProgramStorageObjectImpl(m_implementedInterfaces, this), CProgramStorageObjectImpl(m_implementedInterfaces, this),
CProgrammableObjectImpl(m_implementedInterfaces, this), CProgrammableObjectImpl(m_implementedInterfaces, this),
CJostleableObject(m_implementedInterfaces), CJostleableObject(m_implementedInterfaces),
CCarrierObject(m_implementedInterfaces), CSlottedObject(m_implementedInterfaces),
CPoweredObject(m_implementedInterfaces),
CJetFlyingObject(m_implementedInterfaces), CJetFlyingObject(m_implementedInterfaces),
CControllableObject(m_implementedInterfaces), CControllableObject(m_implementedInterfaces),
CPowerContainerObjectImpl(m_implementedInterfaces), CPowerContainerObjectImpl(m_implementedInterfaces),
@ -145,6 +144,8 @@ COldObject::COldObject(int id)
m_gunGoalH = 0.0f; m_gunGoalH = 0.0f;
m_shieldRadius = 0.0f; m_shieldRadius = 0.0f;
m_magnifyDamage = 1.0f; m_magnifyDamage = 1.0f;
m_hasPowerSlot = false;
m_hasCargoSlot = false;
m_character = Character(); m_character = Character();
m_character.wheelFront = 1.0f; m_character.wheelFront = 1.0f;
@ -774,17 +775,34 @@ void COldObject::SetType(ObjectType type)
m_type == OBJECT_MOBILEst || m_type == OBJECT_MOBILEst ||
m_type == OBJECT_TOWER || m_type == OBJECT_TOWER ||
m_type == OBJECT_RESEARCH || m_type == OBJECT_RESEARCH ||
m_type == OBJECT_ENERGY || m_type == OBJECT_ENERGY || // TODO not actually a power cell slot
m_type == OBJECT_LABO || m_type == OBJECT_LABO || // TODO not actually a power cell slot
m_type == OBJECT_NUCLEAR ) m_type == OBJECT_NUCLEAR ) // TODO not actually a power cell slot
{ {
m_implementedInterfaces[static_cast<int>(ObjectInterfaceType::Powered)] = true; m_hasPowerSlot = true;
} }
else else
{ {
m_implementedInterfaces[static_cast<int>(ObjectInterfaceType::Powered)] = false; m_hasPowerSlot = false;
} }
if ( m_type == OBJECT_HUMAN ||
m_type == OBJECT_TECH ||
m_type == OBJECT_MOBILEfa || // Grabbers
m_type == OBJECT_MOBILEta ||
m_type == OBJECT_MOBILEwa ||
m_type == OBJECT_MOBILEia ||
m_type == OBJECT_MOBILEsa) // subber
{
m_hasCargoSlot = true;
}
else
{
m_hasCargoSlot = false;
}
m_implementedInterfaces[static_cast<int>(ObjectInterfaceType::Slotted)] = (m_hasPowerSlot || m_hasCargoSlot);
// TODO: Hacking some more // TODO: Hacking some more
if ( m_type == OBJECT_MOBILEtg || if ( m_type == OBJECT_MOBILEtg ||
m_type == OBJECT_STONE || m_type == OBJECT_STONE ||
@ -1662,39 +1680,135 @@ void COldObject::SetMasterParticle(int part, int parti)
// Management of the stack transport. // Management of the stack transport.
void COldObject::SetPower(CObject* power)
{
m_power = power;
}
CObject* COldObject::GetPower() int COldObject::GetNumSlots()
{ {
return m_power; assert(m_hasPowerSlot || m_hasCargoSlot); // otherwise implemented[CSlottedObject] is false
return (m_hasPowerSlot ? 1 : 0) + (m_hasCargoSlot ? 1 : 0);
} }
int COldObject::MapPseudoSlot(Pseudoslot pseudoslot)
{
switch (pseudoslot)
{
case Pseudoslot::POWER:
return m_hasPowerSlot ? 0 : -1;
case Pseudoslot::CARRYING:
return m_hasCargoSlot ? (m_hasPowerSlot ? 1 : 0) : -1;
default:
return -1;
}
}
Math::Vector COldObject::GetSlotPosition(int slotNum)
{
if (slotNum == 0 && m_hasPowerSlot)
return m_powerPosition;
else
{
assert(m_hasCargoSlot && slotNum == (m_hasPowerSlot ? 1 : 0));
int grabPartNum;
Math::Vector grabRelPos;
// See CTaskManip::TransporterTakeObject call to SetTransporterPart and SetPosition
switch (m_type)
{
case OBJECT_HUMAN:
case OBJECT_TECH:
grabPartNum = 4;
grabRelPos = Math::Vector(1.7f, -0.5f, 1.1f);
break;
case OBJECT_MOBILEsa: // subber
grabPartNum = 2;
grabRelPos = Math::Vector(1.1f, -1.0f, 1.0f);
break;
case OBJECT_MOBILEfa: // Grabbers
case OBJECT_MOBILEta:
case OBJECT_MOBILEwa:
case OBJECT_MOBILEia:
grabPartNum = 3;
grabRelPos = Math::Vector(4.7f, 0.0f, 0.0f);
break;
default: // unreachable, only the above objects have cargo slots
assert(!m_hasCargoSlot);
return m_powerPosition;
}
return Math::Transform(GetWorldMatrix(0)->Inverse(), Math::Transform(*GetWorldMatrix(grabPartNum), grabRelPos));
}
}
float COldObject::GetSlotAngle(int slotNum)
{
if (slotNum == 0 && m_hasPowerSlot)
{
switch (m_type)
{
case OBJECT_TOWER:
case OBJECT_RESEARCH:
case OBJECT_ENERGY:
case OBJECT_LABO:
case OBJECT_NUCLEAR:
return 0;
default: // robots
return Math::PI;
}
}
else
{
assert(m_hasCargoSlot && slotNum == (m_hasPowerSlot ? 1 : 0));
return 0;
}
}
float COldObject::GetSlotAcceptanceAngle(int slotNum)
{
if (slotNum == 0 && m_hasPowerSlot)
{
switch (m_type)
{
case OBJECT_TOWER:
case OBJECT_RESEARCH:
return 45.0f*Math::PI/180.0f;
case OBJECT_ENERGY:
return 90.0f*Math::PI/180.0f;
case OBJECT_LABO:
return 120.0f*Math::PI/180.0f;
case OBJECT_NUCLEAR:
return 45.0f*Math::PI/180.0f;
default:
return 45.0f*Math::PI/180.0f;
}
}
else
{
assert(m_hasCargoSlot && slotNum == (m_hasPowerSlot ? 1 : 0));
return 0; // no acceptance angle for cargo slot
}
}
CObject *COldObject::GetSlotContainedObject(int slotNum)
{
if (slotNum == 0 && m_hasPowerSlot)
return m_power;
else
{
assert(m_hasCargoSlot && slotNum == (m_hasPowerSlot ? 1 : 0));
return m_cargo;
}
}
void COldObject::SetSlotContainedObject(int slotNum, CObject *object)
{
if (slotNum == 0 && m_hasPowerSlot)
m_power = object;
else
{
assert(m_hasCargoSlot && slotNum == (m_hasPowerSlot ? 1 : 0));
m_cargo = object;
}
}
// not part of CSlottedObject; just used for initialization
void COldObject::SetPowerPosition(const Math::Vector& powerPosition) void COldObject::SetPowerPosition(const Math::Vector& powerPosition)
{ {
m_powerPosition = powerPosition; m_powerPosition = powerPosition;
} }
Math::Vector COldObject::GetPowerPosition()
{
return m_powerPosition;
}
// Management of the object transport.
void COldObject::SetCargo(CObject* cargo)
{
m_cargo = cargo;
}
CObject* COldObject::GetCargo()
{
return m_cargo;
}
// Management of the object "transporter" that transports it. // Management of the object "transporter" that transports it.
void COldObject::SetTransporter(CObject* transporter) void COldObject::SetTransporter(CObject* transporter)

View File

@ -33,7 +33,6 @@
#include "object/implementation/programmable_impl.h" #include "object/implementation/programmable_impl.h"
#include "object/implementation/task_executor_impl.h" #include "object/implementation/task_executor_impl.h"
#include "object/interface/carrier_object.h"
#include "object/interface/controllable_object.h" #include "object/interface/controllable_object.h"
#include "object/interface/flying_object.h" #include "object/interface/flying_object.h"
#include "object/interface/interactive_object.h" #include "object/interface/interactive_object.h"
@ -41,10 +40,10 @@
#include "object/interface/jostleable_object.h" #include "object/interface/jostleable_object.h"
#include "object/interface/movable_object.h" #include "object/interface/movable_object.h"
#include "object/interface/power_container_object.h" #include "object/interface/power_container_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/programmable_object.h" #include "object/interface/programmable_object.h"
#include "object/interface/ranged_object.h" #include "object/interface/ranged_object.h"
#include "object/interface/shielded_auto_regen_object.h" #include "object/interface/shielded_auto_regen_object.h"
#include "object/interface/slotted_object.h"
#include "object/interface/task_executor_object.h" #include "object/interface/task_executor_object.h"
#include "object/interface/trace_drawing_object.h" #include "object/interface/trace_drawing_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
@ -83,8 +82,7 @@ class COldObject : public CObject,
public CProgramStorageObjectImpl, public CProgramStorageObjectImpl,
public CProgrammableObjectImpl, public CProgrammableObjectImpl,
public CJostleableObject, public CJostleableObject,
public CCarrierObject, public CSlottedObject,
public CPoweredObject,
public CJetFlyingObject, public CJetFlyingObject,
public CControllableObject, public CControllableObject,
public CPowerContainerObjectImpl, public CPowerContainerObjectImpl,
@ -175,12 +173,6 @@ public:
void SetMasterParticle(int part, int parti) override; void SetMasterParticle(int part, int parti) override;
void SetPower(CObject* power) override;
CObject* GetPower() override;
Math::Vector GetPowerPosition() override;
void SetPowerPosition(const Math::Vector& powerPosition) override;
void SetCargo(CObject* cargo) override;
CObject* GetCargo() override;
void SetTransporter(CObject* transporter) override; void SetTransporter(CObject* transporter) override;
CObject* GetTransporter() override; CObject* GetTransporter() override;
void SetTransporterPart(int part) override; void SetTransporterPart(int part) override;
@ -295,6 +287,17 @@ public:
void SetBulletWall(bool bulletWall); void SetBulletWall(bool bulletWall);
bool IsBulletWall() override; bool IsBulletWall() override;
// CSlottedObject
int MapPseudoSlot(Pseudoslot pseudoslot) override;
int GetNumSlots() override;
Math::Vector GetSlotPosition(int slotNum) override;
float GetSlotAngle(int slotNum) override;
float GetSlotAcceptanceAngle(int slotNum) override;
CObject *GetSlotContainedObject(int slotNum) override;
void SetSlotContainedObject(int slotNum, CObject *object) override;
// Helper for CSlottedObject initialization
void SetPowerPosition(const Math::Vector& powerPosition);
protected: protected:
bool EventFrame(const Event &event); bool EventFrame(const Event &event);
void VirusFrame(float rTime); void VirusFrame(float rTime);
@ -393,4 +396,7 @@ protected:
float m_traceWidth; float m_traceWidth;
bool m_bulletWall = false; bool m_bulletWall = false;
bool m_hasCargoSlot;
bool m_hasPowerSlot;
}; };

View File

@ -36,7 +36,6 @@
#include "object/auto/auto.h" #include "object/auto/auto.h"
#include "object/interface/carrier_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "object/motion/motionhuman.h" #include "object/motion/motionhuman.h"

View File

@ -26,6 +26,8 @@
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/slotted_object.h"
#include "physics/physics.h" #include "physics/physics.h"
#include "sound/sound.h" #include "sound/sound.h"
@ -42,7 +44,7 @@ CTaskFire::CTaskFire(COldObject* object) : CForegroundTask(object)
{ {
m_soundChannel = -1; m_soundChannel = -1;
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
} }
// Object's destructor. // Object's destructor.
@ -78,10 +80,8 @@ bool CTaskFire::EventProcess(const Event &event)
m_lastSound -= event.rTime; m_lastSound -= event.rTime;
m_progress += event.rTime*m_speed; m_progress += event.rTime*m_speed;
CPowerContainerObject* power = nullptr; if (CPowerContainerObject* power = GetObjectPowerCell(m_object))
if (m_object->GetPower() != nullptr && m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer))
{ {
power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower());
energy = power->GetEnergy(); energy = power->GetEnergy();
if ( m_bOrganic ) fire = ENERGY_FIREi; if ( m_bOrganic ) fire = ENERGY_FIREi;
else if ( m_bRay ) fire = ENERGY_FIREr; else if ( m_bRay ) fire = ENERGY_FIREr;
@ -313,11 +313,11 @@ Error CTaskFire::Start(float delay)
} }
m_delay = delay; m_delay = delay;
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); CPowerContainerObject *power = GetObjectPowerCell(m_object);
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_FIRE_ENERGY; if (power == nullptr) return ERR_FIRE_ENERGY;
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy(); energy = power->GetEnergy();
if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi; if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi;
else if ( m_bRay ) fire = m_delay*ENERGY_FIREr; else if ( m_bRay ) fire = m_delay*ENERGY_FIREr;
else fire = m_delay*ENERGY_FIRE; else fire = m_delay*ENERGY_FIRE;

View File

@ -28,8 +28,6 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h"
#include "object/motion/motionhuman.h" #include "object/motion/motionhuman.h"
#include "physics/physics.h" #include "physics/physics.h"

View File

@ -33,6 +33,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "object/subclass/base_alien.h" #include "object/subclass/base_alien.h"
@ -1201,8 +1202,11 @@ bool CTaskGoto::AdjustTarget(CObject* pObj, Math::Vector &pos, float &distance)
type == OBJECT_MOBILEst || type == OBJECT_MOBILEst ||
type == OBJECT_MOBILEdr ) type == OBJECT_MOBILEdr )
{ {
assert(pObj->Implements(ObjectInterfaceType::Powered)); CSlottedObject *asSlotted = dynamic_cast<CSlottedObject*>(pObj);
pos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition(); int powerSlotIndex = asSlotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER);
assert(powerSlotIndex >= 0);
pos = asSlotted->GetSlotPosition(powerSlotIndex);
// TODO: this only works for a certain slot angle
pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance; pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance;
mat = pObj->GetWorldMatrix(0); mat = pObj->GetWorldMatrix(0);
pos = Transform(*mat, pos); pos = Transform(*mat, pos);

View File

@ -30,14 +30,14 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "physics/physics.h" #include "physics/physics.h"
#include "sound/sound.h" #include "sound/sound.h"
const int INVALID_SLOT = -1;
//?const float MARGIN_FRONT = 2.0f; //?const float MARGIN_FRONT = 2.0f;
//?const float MARGIN_BACK = 2.0f; //?const float MARGIN_BACK = 2.0f;
@ -58,7 +58,7 @@ CTaskManip::CTaskManip(COldObject* object) : CForegroundTask(object)
m_arm = TMA_NEUTRAL; m_arm = TMA_NEUTRAL;
m_hand = TMH_OPEN; m_hand = TMH_OPEN;
assert(m_object->Implements(ObjectInterfaceType::Carrier)); assert(m_object->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING) >= 0);
} }
// Object's destructor. // Object's destructor.
@ -295,7 +295,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
type = m_object->GetType(); type = m_object->GetType();
if ( type == OBJECT_BEE ) // bee? if ( type == OBJECT_BEE ) // bee?
{ {
if (m_object->GetCargo() == nullptr) if (m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr)
{ {
if ( !m_physics->GetLand() ) return ERR_MANIP_FLY; if ( !m_physics->GetLand() ) return ERR_MANIP_FLY;
@ -303,17 +303,17 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if (other == nullptr) return ERR_MANIP_NIL; if (other == nullptr) return ERR_MANIP_NIL;
assert(other->Implements(ObjectInterfaceType::Transportable)); assert(other->Implements(ObjectInterfaceType::Transportable));
m_object->SetCargo(other); // takes the ball m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, other); // takes the ball
dynamic_cast<CTransportableObject&>(*other).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*other).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*other).SetTransporterPart(0); // taken with the base dynamic_cast<CTransportableObject&>(*other).SetTransporterPart(0); // taken with the base
other->SetPosition(Math::Vector(0.0f, -3.0f, 0.0f)); other->SetPosition(Math::Vector(0.0f, -3.0f, 0.0f));
} }
else else
{ {
other = m_object->GetCargo(); // other = ball other = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING); // other = ball
assert(other->Implements(ObjectInterfaceType::Transportable)); assert(other->Implements(ObjectInterfaceType::Transportable));
m_object->SetCargo(nullptr); // lick the ball m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // lick the ball
dynamic_cast<CTransportableObject&>(*other).SetTransporter(nullptr); dynamic_cast<CTransportableObject&>(*other).SetTransporter(nullptr);
pos = m_object->GetPosition(); pos = m_object->GetPosition();
pos.y -= 3.0f; pos.y -= 3.0f;
@ -361,7 +361,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if ( order == TMO_AUTO ) if ( order == TMO_AUTO )
{ {
if (m_object->GetCargo() == nullptr) if (m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr)
{ {
m_order = TMO_GRAB; m_order = TMO_GRAB;
} }
@ -375,11 +375,11 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
m_order = order; m_order = order;
} }
if (m_order == TMO_GRAB && m_object->GetCargo() != nullptr) if (m_order == TMO_GRAB && m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) != nullptr)
{ {
return ERR_MANIP_BUSY; return ERR_MANIP_BUSY;
} }
if (m_order == TMO_DROP && m_object->GetCargo() == nullptr) if (m_order == TMO_DROP && m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr)
{ {
return ERR_MANIP_EMPTY; return ERR_MANIP_EMPTY;
} }
@ -393,7 +393,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if ( m_arm == TMA_FFRONT ) if ( m_arm == TMA_FFRONT )
{ {
front = SearchTakeFrontObject(true, fPos, fDist, fAngle); front = SearchTakeFrontObject(true, fPos, fDist, fAngle);
other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight); int slotNum;
other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight, slotNum);
if ( front != nullptr && fDist < oDist ) if ( front != nullptr && fDist < oDist )
{ {
@ -403,7 +404,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
} }
else if ( other != nullptr && oDist < fDist ) else if ( other != nullptr && oDist < fDist )
{ {
if (! ObjectHasPowerCell(other)) return ERR_MANIP_NIL; if (dynamic_cast<CSlottedObject&>(*other).GetSlotContainedObject(slotNum) == nullptr) return ERR_MANIP_NIL;
m_targetPos = oPos; m_targetPos = oPos;
m_angle = oAngle; m_angle = oAngle;
m_height = oHeight; m_height = oHeight;
@ -427,8 +428,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
} }
if ( m_arm == TMA_POWER ) if ( m_arm == TMA_POWER )
{ {
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
if (m_object->GetPower() == nullptr) return ERR_MANIP_NIL; if (m_object->GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::POWER) == nullptr) return ERR_MANIP_NIL;
} }
} }
@ -436,8 +437,9 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
{ {
if ( m_arm == TMA_FFRONT ) if ( m_arm == TMA_FFRONT )
{ {
other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight); int slotNum;
if (other != nullptr && !ObjectHasPowerCell(other)) other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight, slotNum);
if (other != nullptr && dynamic_cast<CSlottedObject&>(*other).GetSlotContainedObject(slotNum) == nullptr)
{ {
m_targetPos = oPos; m_targetPos = oPos;
m_angle = oAngle; m_angle = oAngle;
@ -456,8 +458,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
} }
if ( m_arm == TMA_POWER ) if ( m_arm == TMA_POWER )
{ {
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
if (m_object->GetPower() != nullptr) return ERR_MANIP_OCC; if (m_object->GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::POWER) != nullptr) return ERR_MANIP_OCC;
} }
} }
@ -477,7 +479,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if ( m_timeLimit < 0.5f ) m_timeLimit = 0.5f; if ( m_timeLimit < 0.5f ) m_timeLimit = 0.5f;
} }
if (m_object->GetCargo() == nullptr) // not carrying anything? if (m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr) // not carrying anything?
{ {
m_hand = TMH_OPEN; // open clamp m_hand = TMH_OPEN; // open clamp
} }
@ -602,7 +604,7 @@ Error CTaskManip::IsEnded()
{ {
if ( m_bSubm ) m_speed = 1.0f/1.5f; if ( m_bSubm ) m_speed = 1.0f/1.5f;
if ( !TransporterTakeObject() && if ( !TransporterTakeObject() &&
m_object->GetCargo() == nullptr) m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr)
{ {
m_hand = TMH_OPEN; // reopens the clamp m_hand = TMH_OPEN; // reopens the clamp
m_arm = TMA_NEUTRAL; m_arm = TMA_NEUTRAL;
@ -613,7 +615,7 @@ Error CTaskManip::IsEnded()
{ {
if ( (m_arm == TMA_OTHER || if ( (m_arm == TMA_OTHER ||
m_arm == TMA_POWER ) && m_arm == TMA_POWER ) &&
m_object->GetCargo()->Implements(ObjectInterfaceType::PowerContainer) ) m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING)->Implements(ObjectInterfaceType::PowerContainer) )
{ {
m_sound->Play(SOUND_POWEROFF, m_object->GetPosition()); m_sound->Play(SOUND_POWEROFF, m_object->GetPosition());
} }
@ -630,7 +632,7 @@ Error CTaskManip::IsEnded()
if ( m_step == 1 ) if ( m_step == 1 )
{ {
if ( m_bSubm ) m_speed = 1.0f/0.7f; if ( m_bSubm ) m_speed = 1.0f/0.7f;
cargo = m_object->GetCargo(); cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (TransporterDeposeObject()) if (TransporterDeposeObject())
{ {
if ( (m_arm == TMA_OTHER || if ( (m_arm == TMA_OTHER ||
@ -667,7 +669,7 @@ Error CTaskManip::IsEnded()
bool CTaskManip::Abort() bool CTaskManip::Abort()
{ {
if (m_object->GetCargo() == nullptr) // not carrying anything? if (m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING) == nullptr) // not carrying anything?
{ {
m_hand = TMH_OPEN; // open clamp m_hand = TMH_OPEN; // open clamp
m_arm = TMA_NEUTRAL; m_arm = TMA_NEUTRAL;
@ -868,10 +870,12 @@ CObject* CTaskManip::SearchTakeBackObject(bool bAdvance, Math::Vector &pos,
CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos, CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
float &distance, float &angle, float &distance, float &angle,
float &height) float &height, int &slotNumOut)
{ {
slotNumOut = INVALID_SLOT;
Math::Matrix* mat; Math::Matrix* mat;
float iAngle, oAngle, oLimit, aLimit, dLimit; float iAngle, aLimit, dLimit;
distance = 1000000.0f; distance = 1000000.0f;
angle = 0.0f; angle = 0.0f;
@ -900,56 +904,45 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
{ {
if ( pObj == m_object ) continue; // yourself? if ( pObj == m_object ) continue; // yourself?
ObjectType type = pObj->GetType(); if (pObj->Implements(ObjectInterfaceType::Slotted))
if ( !pObj->Implements(ObjectInterfaceType::Powered) ) continue;
CObject* power = dynamic_cast<CPoweredObject&>(*pObj).GetPower();
if (power != nullptr)
{ {
if (power->GetLock()) continue; CSlottedObject &obj = dynamic_cast<CSlottedObject&>(*pObj);
if (power->GetScaleY() != 1.0f) continue; int slotNum = obj.GetNumSlots();
} for (int slot = 0; slot < slotNum; slot++)
mat = pObj->GetWorldMatrix(0);
Math::Vector oPos = Transform(*mat, dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition());
oAngle = pObj->GetRotationY();
if ( type == OBJECT_TOWER ||
type == OBJECT_RESEARCH )
{
oLimit = 45.0f*Math::PI/180.0f;
}
else if ( type == OBJECT_ENERGY )
{
oLimit = 90.0f*Math::PI/180.0f;
}
else if ( type == OBJECT_LABO )
{
oLimit = 120.0f*Math::PI/180.0f;
}
else if ( type == OBJECT_NUCLEAR )
{
oLimit = 45.0f*Math::PI/180.0f;
}
else
{
oLimit = 45.0f*Math::PI/180.0f;
oAngle += Math::PI; // is behind
}
oAngle = Math::NormAngle(oAngle); // 0..2*Math::PI
angle = Math::RotateAngle(iPos.x-oPos.x, oPos.z-iPos.z); // CW !
if ( !Math::TestAngle(angle, oAngle-oLimit, oAngle+oLimit) ) continue;
distance = fabs(Math::Distance(oPos, iPos)-TAKE_DIST);
if ( distance <= dLimit )
{
angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
{ {
Math::Vector powerPos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition(); mat = pObj->GetWorldMatrix(0);
height = powerPos.y; Math::Vector worldSlotPos = Transform(*mat, obj.GetSlotPosition(slot));
pos = oPos;
return pObj; CObject *objectInSlot = obj.GetSlotContainedObject(slot);
if (objectInSlot != nullptr && (objectInSlot->GetLock() || objectInSlot->GetScaleY() != 1.0f))
continue;
float objectAngleOffsetLimit = obj.GetSlotAcceptanceAngle(slot);
if(objectAngleOffsetLimit == 0)
continue; // slot isn't take-able
// The robot must be in the correct angle relative to the slot (it can't be on the other side of the object)
float angleFromObjectToRobot = Math::RotateAngle(iPos.x-worldSlotPos.x, worldSlotPos.z-iPos.z); // CW !
float objectIdealAngle = Math::NormAngle(pObj->GetRotationY() + obj.GetSlotAngle(slot));
if ( Math::TestAngle(angleFromObjectToRobot, objectIdealAngle - objectAngleOffsetLimit, objectIdealAngle + objectAngleOffsetLimit) )
{
distance = fabs(Math::Distance(worldSlotPos, iPos)-TAKE_DIST);
// The robot must be close enough to the slot
if ( distance <= dLimit )
{
// The slot must be in the correct position relative to the robot (the robot must be facing towards the slot, not sideways or away)
angle = Math::RotateAngle(worldSlotPos.x-iPos.x, iPos.z-worldSlotPos.z); // CW !
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
{
Math::Vector powerPos = obj.GetSlotPosition(slot);
height = powerPos.y;
pos = worldSlotPos;
slotNumOut = slot;
return pObj;
}
}
}
} }
} }
} }
@ -965,7 +958,7 @@ bool CTaskManip::TransporterTakeObject()
{ {
if (m_arm == TMA_GRAB) // takes immediately? if (m_arm == TMA_GRAB) // takes immediately?
{ {
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; // nothing to take? if (cargo == nullptr) return false; // nothing to take?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
@ -1005,7 +998,7 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
} }
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
if (m_arm == TMA_FFRONT) // takes on the ground in front? if (m_arm == TMA_FFRONT) // takes on the ground in front?
@ -1041,7 +1034,7 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
} }
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
if (m_arm == TMA_FBACK) // takes on the ground behind? if (m_arm == TMA_FBACK) // takes on the ground behind?
@ -1063,13 +1056,13 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationZ(Math::PI/2.0f); cargo->SetRotationZ(Math::PI/2.0f);
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
if (m_arm == TMA_POWER) // takes battery in the back? if (m_arm == TMA_POWER) // takes battery in the back?
{ {
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->Implements(ObjectInterfaceType::Slotted));
CObject* cargo = m_object->GetPower(); CObject* cargo = m_object->GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::POWER);
if (cargo == nullptr) return false; // no battery? if (cargo == nullptr) return false; // no battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
@ -1082,25 +1075,25 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
m_object->SetPower(nullptr); m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER, nullptr);
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
if (m_arm == TMA_OTHER) // battery takes from friend? if (m_arm == TMA_OTHER) // battery takes from friend?
{ {
Math::Vector pos; Math::Vector pos;
float dist = 0.0f, angle = 0.0f; float dist = 0.0f, angle = 0.0f;
CObject* other = SearchOtherObject(false, pos, dist, angle, m_height); int slotNum;
CObject* other = SearchOtherObject(false, pos, dist, angle, m_height, slotNum);
if (other == nullptr) return false; if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered)); assert(slotNum != INVALID_SLOT);
CObject *cargo = dynamic_cast<CSlottedObject&>(*other).GetSlotContainedObject(slotNum);
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower();
if (cargo == nullptr) return false; // the other does not have a battery? if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType(); m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject&>(*other).SetPower(nullptr); dynamic_cast<CSlottedObject&>(*other).SetSlotContainedObject(slotNum, nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
@ -1110,7 +1103,7 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationZ(Math::PI/2.0f); cargo->SetRotationZ(Math::PI/2.0f);
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
return true; return true;
@ -1122,7 +1115,7 @@ bool CTaskManip::TransporterDeposeObject()
{ {
if (m_arm == TMA_FFRONT) // deposits on the ground in front? if (m_arm == TMA_FFRONT) // deposits on the ground in front?
{ {
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; // nothing transported? if (cargo == nullptr) return false; // nothing transported?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
@ -1138,12 +1131,12 @@ bool CTaskManip::TransporterDeposeObject()
cargo->FloorAdjust(); // plate well on the ground cargo->FloorAdjust(); // plate well on the ground
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // deposit
} }
if (m_arm == TMA_FBACK) // deposited on the ground behind? if (m_arm == TMA_FBACK) // deposited on the ground behind?
{ {
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; // nothing transported? if (cargo == nullptr) return false; // nothing transported?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
@ -1158,30 +1151,32 @@ bool CTaskManip::TransporterDeposeObject()
cargo->SetRotationZ(0.0f); cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // deposit
} }
if (m_arm == TMA_POWER) // deposits battery in the back? if (m_arm == TMA_POWER) // deposits battery in the back?
{ {
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->Implements(ObjectInterfaceType::Slotted));
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; // nothing transported? if (cargo == nullptr) return false; // nothing transported?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType(); m_cargoType = cargo->GetType();
if (m_object->GetPower() != nullptr) return false; int powerSlotIndex = m_object->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER);
assert(powerSlotIndex >= 0);
if (m_object->GetSlotContainedObject(powerSlotIndex) != nullptr) return false;
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
cargo->SetPosition(m_object->GetPowerPosition()); cargo->SetPosition(m_object->GetSlotPosition(powerSlotIndex));
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f); cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f); cargo->SetRotationZ(0.0f);
m_object->SetPower(cargo); // uses m_object->SetSlotContainedObject(powerSlotIndex, cargo); // uses
m_object->SetCargo(nullptr); m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr);
} }
if (m_arm == TMA_OTHER) // deposits battery on friend? if (m_arm == TMA_OTHER) // deposits battery on friend?
@ -1189,29 +1184,30 @@ bool CTaskManip::TransporterDeposeObject()
Math::Vector pos; Math::Vector pos;
float angle = 0.0f, dist = 0.0f; float angle = 0.0f, dist = 0.0f;
CObject* other = SearchOtherObject(false, pos, dist, angle, m_height); int slotNum;
CObject* other = SearchOtherObject(false, pos, dist, angle, m_height, slotNum);
if (other == nullptr) return false; if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered)); assert(slotNum != INVALID_SLOT);
CSlottedObject *otherAsSlotted = dynamic_cast<CSlottedObject*>(other);
if (otherAsSlotted->GetSlotContainedObject(slotNum) != nullptr) return false; // the other already has a battery?
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower(); CObject *cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo != nullptr) return false; // the other already has a battery?
cargo = m_object->GetCargo();
if (cargo == nullptr) return false; if (cargo == nullptr) return false;
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType(); m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject&>(*other).SetPower(cargo); otherAsSlotted->SetSlotContainedObject(slotNum, cargo);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other);
cargo->SetPosition(dynamic_cast<CPoweredObject&>(*other).GetPowerPosition()); // TODO: isn't this wrong? PowerPosition (and SlotContainedPosition) is an object-local position.
cargo->SetPosition(otherAsSlotted->GetSlotPosition(slotNum));
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f); cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f); cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
m_object->SetCargo(nullptr); // deposit m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // deposit
} }
return true; return true;

View File

@ -73,7 +73,7 @@ protected:
CObject* SearchTakeUnderObject(Math::Vector &pos, float dLimit); CObject* SearchTakeUnderObject(Math::Vector &pos, float dLimit);
CObject* SearchTakeFrontObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle); CObject* SearchTakeFrontObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle);
CObject* SearchTakeBackObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle); CObject* SearchTakeBackObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle);
CObject* SearchOtherObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle, float &height); CObject* SearchOtherObject(bool bAdvance, Math::Vector &pos, float &distance, float &angle, float &height, int &slotNumOut);
bool TransporterTakeObject(); bool TransporterTakeObject();
bool TransporterDeposeObject(); bool TransporterDeposeObject();
bool IsFreeDeposeObject(Math::Vector pos); bool IsFreeDeposeObject(Math::Vector pos);

View File

@ -31,7 +31,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "physics/physics.h" #include "physics/physics.h"
@ -108,11 +108,9 @@ bool CTaskRecover::EventProcess(const Event &event)
if ( m_phase == TRP_OPER ) if ( m_phase == TRP_OPER )
{ {
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
CObject* powerObj = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); if (CPowerContainerObject* power = GetObjectPowerCell(m_object))
if (powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{ {
CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(powerObj);
energy = power->GetEnergy(); energy = power->GetEnergy();
energy -= event.rTime * ENERGY_RECOVER * m_speed; energy -= event.rTime * ENERGY_RECOVER * m_speed;
power->SetEnergy(energy); power->SetEnergy(energy);
@ -190,11 +188,10 @@ Error CTaskRecover::Start()
ObjectType type = m_object->GetType(); ObjectType type = m_object->GetType();
if ( type != OBJECT_MOBILErr ) return ERR_WRONG_BOT; if ( type != OBJECT_MOBILErr ) return ERR_WRONG_BOT;
assert(m_object->Implements(ObjectInterfaceType::Powered)); CPowerContainerObject *power = GetObjectPowerCell(m_object);
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); if (power == nullptr) return ERR_RECOVER_ENERGY;
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_RECOVER_ENERGY;
float energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy(); float energy = power->GetEnergy();
if ( energy < ENERGY_RECOVER+0.05f ) return ERR_RECOVER_ENERGY; if ( energy < ENERGY_RECOVER+0.05f ) return ERR_RECOVER_ENERGY;
Math::Matrix* mat = m_object->GetWorldMatrix(0); Math::Matrix* mat = m_object->GetWorldMatrix(0);

View File

@ -32,7 +32,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/subclass/shielder.h" #include "object/subclass/shielder.h"
@ -54,7 +54,7 @@ CTaskShield::CTaskShield(COldObject* object) : CBackgroundTask(object)
m_soundChannel = -1; m_soundChannel = -1;
m_effectLight = -1; m_effectLight = -1;
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(HasPowerCellSlot(m_object));
m_shielder = dynamic_cast<CShielder*>(object); m_shielder = dynamic_cast<CShielder*>(object);
} }
@ -118,12 +118,8 @@ bool CTaskShield::EventProcess(const Event &event)
{ {
energy = (1.0f/ENERGY_TIME)*event.rTime; energy = (1.0f/ENERGY_TIME)*event.rTime;
energy *= GetRadius()/RADIUS_SHIELD_MAX; energy *= GetRadius()/RADIUS_SHIELD_MAX;
CObject* powerObj = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); if (CPowerContainerObject *power = GetObjectPowerCell(m_object))
if (powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{
CPowerContainerObject* power = dynamic_cast<CPowerContainerObject*>(powerObj);
power->SetEnergy(power->GetEnergy()-energy); power->SetEnergy(power->GetEnergy()-energy);
}
m_energyUsed += energy; m_energyUsed += energy;
if ( m_soundChannel == -1 ) if ( m_soundChannel == -1 )
@ -307,9 +303,9 @@ Error CTaskShield::Start(TaskShieldMode mode, float delay)
m_bError = true; // operation impossible m_bError = true; // operation impossible
if ( !m_physics->GetLand() ) return ERR_WRONG_BOT; if ( !m_physics->GetLand() ) return ERR_WRONG_BOT;
CObject* power = m_object->GetPower(); CPowerContainerObject* power = GetObjectPowerCell(m_object);
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_SHIELD_ENERGY; if (power == nullptr) return ERR_SHIELD_ENERGY;
float energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy(); float energy = power->GetEnergy();
if ( energy == 0.0f ) return ERR_SHIELD_ENERGY; if ( energy == 0.0f ) return ERR_SHIELD_ENERGY;
Math::Matrix* mat = m_object->GetWorldMatrix(0); Math::Matrix* mat = m_object->GetWorldMatrix(0);

View File

@ -30,8 +30,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "object/motion/motionhuman.h" #include "object/motion/motionhuman.h"
@ -49,7 +48,7 @@ CTaskTake::CTaskTake(COldObject* object) : CForegroundTask(object)
{ {
m_arm = TTA_NEUTRAL; m_arm = TTA_NEUTRAL;
assert(m_object->Implements(ObjectInterfaceType::Carrier)); assert(m_object->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING) >= 0);
} }
// Object's destructor. // Object's destructor.
@ -116,7 +115,7 @@ Error CTaskTake::Start()
m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f)); m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f));
if (m_object->IsCarryingCargo()) if (m_object->GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::CARRYING) != nullptr)
m_order = TTO_DEPOSE; m_order = TTO_DEPOSE;
else else
m_order = TTO_TAKE; m_order = TTO_TAKE;
@ -128,12 +127,14 @@ Error CTaskTake::Start()
float h = m_water->GetLevel(m_object); float h = m_water->GetLevel(m_object);
if ( pos.y < h ) return ERR_MANIP_WATER; // impossible under water if ( pos.y < h ) return ERR_MANIP_WATER; // impossible under water
CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f); int otherSlotNum = -1;
if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered)); CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f, otherSlotNum);
CSlottedObject* otherAsSlotted = dynamic_cast<CSlottedObject*>(other);
assert(other == nullptr || otherSlotNum >= 0);
if (other != nullptr && dynamic_cast<CPoweredObject&>(*other).GetPower() != nullptr) if (other != nullptr && otherAsSlotted->GetSlotContainedObject(otherSlotNum) != nullptr)
{ {
CObject* power = dynamic_cast<CPoweredObject&>(*other).GetPower(); CObject* power = otherAsSlotted->GetSlotContainedObject(otherSlotNum);
type = power->GetType(); type = power->GetType();
if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO; if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
assert(power->Implements(ObjectInterfaceType::Transportable)); assert(power->Implements(ObjectInterfaceType::Transportable));
@ -158,10 +159,12 @@ Error CTaskTake::Start()
//? if ( speed.x != 0.0f || //? if ( speed.x != 0.0f ||
//? speed.z != 0.0f ) return ERR_MANIP_MOTOR; //? speed.z != 0.0f ) return ERR_MANIP_MOTOR;
CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f); int otherSlotNum = -1;
if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered)); CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f, otherSlotNum);
CSlottedObject* otherAsSlotted = dynamic_cast<CSlottedObject*>(other);
assert(other == nullptr || otherSlotNum >= 0);
if (other != nullptr && dynamic_cast<CPoweredObject&>(*other).GetPower() == nullptr ) if (other != nullptr && otherAsSlotted->GetSlotContainedObject(otherSlotNum) == nullptr)
{ {
//? m_camera->StartCentering(m_object, Math::PI*0.3f, -Math::PI*0.1f, 0.0f, 0.8f); //? m_camera->StartCentering(m_object, Math::PI*0.3f, -Math::PI*0.1f, 0.0f, 0.8f);
m_arm = TTA_FRIEND; m_arm = TTA_FRIEND;
@ -233,7 +236,7 @@ Error CTaskTake::IsEnded()
if ( TransporterTakeObject() ) if ( TransporterTakeObject() )
{ {
if ( m_arm == TTA_FRIEND && if ( m_arm == TTA_FRIEND &&
m_object->GetCargo()->Implements(ObjectInterfaceType::PowerContainer) ) m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING)->Implements(ObjectInterfaceType::PowerContainer) )
{ {
m_sound->Play(SOUND_POWEROFF, m_object->GetPosition()); m_sound->Play(SOUND_POWEROFF, m_object->GetPosition());
} }
@ -250,7 +253,7 @@ Error CTaskTake::IsEnded()
{ {
if ( m_step == 1 ) if ( m_step == 1 )
{ {
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
TransporterDeposeObject(); TransporterDeposeObject();
if ( m_arm == TTA_FRIEND && if ( m_arm == TTA_FRIEND &&
cargo->Implements(ObjectInterfaceType::PowerContainer) ) cargo->Implements(ObjectInterfaceType::PowerContainer) )
@ -334,7 +337,8 @@ CObject* CTaskTake::SearchTakeObject(float &angle,
// Seeks the robot on which you want take or put a battery. // Seeks the robot on which you want take or put a battery.
CObject* CTaskTake::SearchFriendObject(float &angle, CObject* CTaskTake::SearchFriendObject(float &angle,
float dLimit, float aLimit) float dLimit, float aLimit,
int &slotNumOut)
{ {
if (m_object->GetCrashSphereCount() == 0) return nullptr; if (m_object->GetCrashSphereCount() == 0) return nullptr;
@ -348,67 +352,44 @@ CObject* CTaskTake::SearchFriendObject(float &angle,
for (CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects()) for (CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects())
{ {
if ( pObj == m_object ) continue; // yourself? if ( pObj == m_object ) continue; // yourself?
if (!pObj->Implements(ObjectInterfaceType::Slotted)) continue;
ObjectType type = pObj->GetType(); CSlottedObject *obj = dynamic_cast<CSlottedObject*>(pObj);
if ( type != OBJECT_MOBILEfa &&
type != OBJECT_MOBILEta &&
type != OBJECT_MOBILEwa &&
type != OBJECT_MOBILEia &&
type != OBJECT_MOBILEfb &&
type != OBJECT_MOBILEtb &&
type != OBJECT_MOBILEwb &&
type != OBJECT_MOBILEib &&
type != OBJECT_MOBILEfc &&
type != OBJECT_MOBILEtc &&
type != OBJECT_MOBILEwc &&
type != OBJECT_MOBILEic &&
type != OBJECT_MOBILEfi &&
type != OBJECT_MOBILEti &&
type != OBJECT_MOBILEwi &&
type != OBJECT_MOBILEii &&
type != OBJECT_MOBILEfs &&
type != OBJECT_MOBILEts &&
type != OBJECT_MOBILEws &&
type != OBJECT_MOBILEis &&
type != OBJECT_MOBILErt &&
type != OBJECT_MOBILErc &&
type != OBJECT_MOBILErr &&
type != OBJECT_MOBILErs &&
type != OBJECT_MOBILEsa &&
type != OBJECT_MOBILEtg &&
type != OBJECT_MOBILEft &&
type != OBJECT_MOBILEtt &&
type != OBJECT_MOBILEwt &&
type != OBJECT_MOBILEit &&
type != OBJECT_MOBILErp &&
type != OBJECT_MOBILEst &&
type != OBJECT_TOWER &&
type != OBJECT_RESEARCH &&
type != OBJECT_ENERGY &&
type != OBJECT_LABO &&
type != OBJECT_NUCLEAR ) continue;
assert(pObj->Implements(ObjectInterfaceType::Powered)); int slotNum = obj->GetNumSlots();
for (int slot = 0; slot < slotNum; slot++)
CObject* power = dynamic_cast<CPoweredObject&>(*pObj).GetPower();
if (power != nullptr)
{ {
if ( power->GetLock() ) continue; CObject *objectInSlot = obj->GetSlotContainedObject(slot);
if ( power->GetScaleY() != 1.0f ) continue; if (objectInSlot != nullptr && (objectInSlot->GetLock() || objectInSlot->GetScaleY() != 1.0f))
} continue;
Math::Matrix* mat = pObj->GetWorldMatrix(0); float objectAngleOffsetLimit = obj->GetSlotAcceptanceAngle(slot);
Math::Vector oPos = Math::Transform(*mat, dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition()); if (objectAngleOffsetLimit == 0)
continue; // slot isn't take-able
float distance = fabs(Math::Distance(oPos, iPos) - (iRad+1.0f)); Math::Matrix* mat = pObj->GetWorldMatrix(0);
if ( distance <= dLimit ) Math::Vector worldSlotPos = Transform(*mat, obj->GetSlotPosition(slot));
{
angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW ! // The robot must be in the correct angle relative to the slot (it can't be on the other side of the object)
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) ) float angleFromObjectToRobot = Math::RotateAngle(iPos.x-worldSlotPos.x, worldSlotPos.z-iPos.z); // CW !
float objectIdealAngle = Math::NormAngle(pObj->GetRotationY() + obj->GetSlotAngle(slot));
if ( Math::TestAngle(angleFromObjectToRobot, objectIdealAngle - objectAngleOffsetLimit, objectIdealAngle + objectAngleOffsetLimit) )
{ {
Math::Vector powerPos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition(); float distance = fabs(Math::Distance(worldSlotPos, iPos)-(iRad + 1.0f));
m_height = powerPos.y; // The robot must be close enough to the slot
return pObj; if ( distance <= dLimit )
{
// The slot must be in the correct position relative to the robot (the robot must be facing towards the slot, not sideways or away)
angle = Math::RotateAngle(worldSlotPos.x-iPos.x, iPos.z-worldSlotPos.z); // CW !
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
{
Math::Vector powerPos = obj->GetSlotPosition(slot);
m_height = powerPos.y;
slotNumOut = slot;
return pObj;
}
}
} }
} }
} }
@ -439,23 +420,25 @@ bool CTaskTake::TransporterTakeObject()
cargo->SetRotationX(0.0f); cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.8f); cargo->SetRotationZ(0.8f);
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
if (m_arm == TTA_FRIEND) // takes friend's battery? if (m_arm == TTA_FRIEND) // takes friend's battery?
{ {
float angle = 0.0f; float angle = 0.0f;
CObject* other = SearchFriendObject(angle, 1.5f, Math::PI*0.04f); int otherSlotNum = -1;
CObject* other = SearchFriendObject(angle, 1.5f, Math::PI*0.04f, otherSlotNum);
if (other == nullptr) return false; if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered)); CSlottedObject* otherAsSlotted = dynamic_cast<CSlottedObject*>(other);
assert(otherSlotNum >= -1);
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower(); CObject* cargo = otherAsSlotted->GetSlotContainedObject(otherSlotNum);
if (cargo == nullptr) return false; // the other does not have a battery? if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType(); m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject&>(*other).SetPower(nullptr); otherAsSlotted->SetSlotContainedObject(otherSlotNum, nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(4); // takes with the hand dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(4); // takes with the hand
@ -465,7 +448,7 @@ bool CTaskTake::TransporterTakeObject()
cargo->SetRotationX(0.0f); cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.8f); cargo->SetRotationZ(0.8f);
m_object->SetCargo(cargo); // takes m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, cargo); // takes
} }
return true; return true;
@ -477,7 +460,7 @@ bool CTaskTake::TransporterDeposeObject()
{ {
if ( m_arm == TTA_FFRONT ) // deposes on the ground in front? if ( m_arm == TTA_FFRONT ) // deposes on the ground in front?
{ {
CObject* cargo = m_object->GetCargo(); CObject* cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; // does nothing? if (cargo == nullptr) return false; // does nothing?
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
@ -493,34 +476,36 @@ bool CTaskTake::TransporterDeposeObject()
cargo->FloorAdjust(); // plate well on the ground cargo->FloorAdjust(); // plate well on the ground
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // deposit
} }
if ( m_arm == TTA_FRIEND ) // deposes battery on friends? if ( m_arm == TTA_FRIEND ) // deposes battery on friends?
{ {
float angle = 0.0f; float angle = 0.0f;
CObject* other = SearchFriendObject(angle, 1.5f, Math::PI*0.04f); int otherSlotNum = -1;
CObject* other = SearchFriendObject(angle, 1.5f, Math::PI*0.04f, otherSlotNum);
if (other == nullptr) return false; if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered)); CSlottedObject* otherAsSlotted = dynamic_cast<CSlottedObject*>(other);
assert(otherSlotNum >= 0);
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower(); CObject* cargo = otherAsSlotted->GetSlotContainedObject(otherSlotNum);
if (cargo != nullptr) return false; // the other already has a battery? if (cargo != nullptr) return false; // the other already has a battery?
cargo = m_object->GetCargo(); cargo = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) return false; if (cargo == nullptr) return false;
assert(cargo->Implements(ObjectInterfaceType::Transportable)); assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType(); m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject&>(*other).SetPower(cargo); otherAsSlotted->SetSlotContainedObject(otherSlotNum, cargo);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other);
cargo->SetPosition(dynamic_cast<CPoweredObject&>(*other).GetPowerPosition()); cargo->SetPosition(otherAsSlotted->GetSlotPosition(otherSlotNum));
cargo->SetRotationY(0.0f); cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f); cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f); cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
m_object->SetCargo(nullptr); // deposit m_object->SetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING, nullptr); // deposit
} }
return true; return true;

View File

@ -57,7 +57,7 @@ public:
protected: protected:
CObject* SearchTakeObject(float &angle, float dLimit, float aLimit); CObject* SearchTakeObject(float &angle, float dLimit, float aLimit);
CObject* SearchFriendObject(float &angle, float dLimit, float aLimit); CObject* SearchFriendObject(float &angle, float dLimit, float aLimit, int &slotNumOut);
bool TransporterTakeObject(); bool TransporterTakeObject();
bool TransporterDeposeObject(); bool TransporterDeposeObject();
bool IsFreeDeposeObject(Math::Vector pos); bool IsFreeDeposeObject(Math::Vector pos);

View File

@ -30,7 +30,7 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/motion/motionant.h" #include "object/motion/motionant.h"
#include "object/motion/motionspider.h" #include "object/motion/motionspider.h"
@ -54,7 +54,7 @@ CTaskTerraform::CTaskTerraform(COldObject* object) : CForegroundTask(object)
m_lastParticle = 0.0f; m_lastParticle = 0.0f;
m_soundChannel = -1; m_soundChannel = -1;
assert(m_object->Implements(ObjectInterfaceType::Powered)); assert(m_object->GetNumSlots() == 1);
} }
// Object's destructor. // Object's destructor.
@ -97,7 +97,7 @@ bool CTaskTerraform::EventProcess(const Event &event)
m_object->SetScale(1.0f+m_progress*0.2f); m_object->SetScale(1.0f+m_progress*0.2f);
power = m_object->GetPower(); power = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER);
if (power != nullptr) if (power != nullptr)
{ {
power->SetScale(1.0f+m_progress*1.0f); power->SetScale(1.0f+m_progress*1.0f);
@ -213,7 +213,7 @@ Error CTaskTerraform::Start()
type = m_object->GetType(); type = m_object->GetType();
if ( type != OBJECT_MOBILErt ) return ERR_WRONG_BOT; if ( type != OBJECT_MOBILErt ) return ERR_WRONG_BOT;
power = m_object->GetPower(); power = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER);
if ( power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer) ) return ERR_TERRA_ENERGY; if ( power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer) ) return ERR_TERRA_ENERGY;
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy(); energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
if ( energy < ENERGY_TERRA+0.05f ) return ERR_TERRA_ENERGY; if ( energy < ENERGY_TERRA+0.05f ) return ERR_TERRA_ENERGY;
@ -269,7 +269,7 @@ Error CTaskTerraform::IsEnded()
m_object->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f)); m_object->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f));
m_object->SetScale(1.0f); m_object->SetScale(1.0f);
power = m_object->GetPower(); power = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER);
if (power != nullptr) if (power != nullptr)
{ {
power->SetScale(1.0f); power->SetScale(1.0f);
@ -335,7 +335,7 @@ bool CTaskTerraform::Abort()
m_object->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f)); m_object->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f));
m_object->SetScale(1.0f); m_object->SetScale(1.0f);
power = m_object->GetPower(); power = m_object->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER);
if (power != nullptr) if (power != nullptr)
{ {
power->SetScale(1.0f); power->SetScale(1.0f);

View File

@ -43,9 +43,8 @@
#include "object/object_manager.h" #include "object/object_manager.h"
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h"
#include "object/interface/jostleable_object.h" #include "object/interface/jostleable_object.h"
#include "object/interface/powered_object.h" #include "object/interface/slotted_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include "object/motion/motion.h" #include "object/motion/motion.h"
@ -802,9 +801,9 @@ void CPhysics::MotorUpdate(float aTime, float rTime)
} }
} }
if (m_object->Implements(ObjectInterfaceType::Powered)) if (HasPowerCellSlot(m_object))
{ {
power = dynamic_cast<CPowerContainerObject*>(dynamic_cast<CPoweredObject&>(*m_object).GetPower()); // searches for the object battery uses power = GetObjectPowerCell(m_object); // searches for the object battery uses
if ( GetObjectEnergy(m_object) == 0.0f ) // no battery or flat? if ( GetObjectEnergy(m_object) == 0.0f ) // no battery or flat?
{ {
motorSpeed.x = 0.0f; motorSpeed.x = 0.0f;
@ -2966,10 +2965,11 @@ void CPhysics::PowerParticle(float factor, bool bBreak)
Math::Point dim; Math::Point dim;
bool bCarryPower; bool bCarryPower;
// TODO: it should be all slots that contain a power cell that can get recharged. Not just the carrying slot.
bCarryPower = false; bCarryPower = false;
if (m_object->Implements(ObjectInterfaceType::Carrier)) if (m_object->Implements(ObjectInterfaceType::Slotted))
{ {
CObject* cargo = dynamic_cast<CCarrierObject&>(*m_object).GetCargo(); CObject* cargo = dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::CARRYING);
if ( cargo != nullptr && cargo->Implements(ObjectInterfaceType::PowerContainer) && if ( cargo != nullptr && cargo->Implements(ObjectInterfaceType::PowerContainer) &&
dynamic_cast<CPowerContainerObject&>(*cargo).IsRechargeable() && dynamic_cast<CPowerContainerObject&>(*cargo).IsRechargeable() &&
m_object->GetPartRotationZ(1) == ARM_STOCK_ANGLE1 ) m_object->GetPartRotationZ(1) == ARM_STOCK_ANGLE1 )
@ -2980,7 +2980,7 @@ void CPhysics::PowerParticle(float factor, bool bBreak)
mat = m_object->GetWorldMatrix(0); mat = m_object->GetWorldMatrix(0);
pos = m_object->GetPowerPosition(); pos = m_object->GetSlotPosition(m_object->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER));
pos.x -= 0.3f; pos.x -= 0.3f;
pos.y += 1.0f; // battery center position pos.y += 1.0f; // battery center position
pos = Transform(*mat, pos); pos = Transform(*mat, pos);
@ -3784,16 +3784,16 @@ Error CPhysics::GetError()
} }
} }
if (m_object->Implements(ObjectInterfaceType::Powered)) if (HasPowerCellSlot(m_object))
{ {
CObject* power = dynamic_cast<CPoweredObject&>(*m_object).GetPower(); // searches for the object battery used CPowerContainerObject* power = GetObjectPowerCell(m_object); // searches for the object battery used
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) if (power == nullptr)
{ {
return ERR_VEH_POWER; return ERR_VEH_POWER;
} }
else else
{ {
if ( dynamic_cast<CPowerContainerObject&>(*power).GetEnergy() == 0.0f ) return ERR_VEH_ENERGY; if ( power->GetEnergy() == 0.0f ) return ERR_VEH_ENERGY;
} }
} }

View File

@ -744,15 +744,18 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo
} }
else else
{ {
if (obj->Implements(ObjectInterfaceType::Old)) if (obj->Implements(ObjectInterfaceType::Slotted))
{ {
COldObject* oldobj = dynamic_cast<COldObject*>(obj); CSlottedObject* slotted = dynamic_cast<CSlottedObject*>(obj);
if (oldobj->GetPower() != nullptr) for (int slotNum = slotted->GetNumSlots() - 1; slotNum >= 0; slotNum--)
CObjectManager::GetInstancePointer()->DeleteObject(oldobj->GetPower()); {
if (oldobj->GetCargo() != nullptr) CObject* sub = slotted->GetSlotContainedObject(slotNum);
CObjectManager::GetInstancePointer()->DeleteObject(oldobj->GetCargo()); if (sub != nullptr)
oldobj->SetPower(nullptr); {
oldobj->SetCargo(nullptr); slotted->SetSlotContainedObject(slotNum, nullptr);
CObjectManager::GetInstancePointer()->DeleteObject(sub);
}
}
} }
CObjectManager::GetInstancePointer()->DeleteObject(obj); CObjectManager::GetInstancePointer()->DeleteObject(obj);
} }
@ -3687,9 +3690,10 @@ void CScriptFunctions::uObject(CBotVar* botThis, void* user)
// Updates the type of battery. // Updates the type of battery.
pVar = pVar->GetNext(); // "energyCell" pVar = pVar->GetNext(); // "energyCell"
if (object->Implements(ObjectInterfaceType::Powered)) CSlottedObject *asSlotted = object->Implements(ObjectInterfaceType::Slotted) ? dynamic_cast<CSlottedObject*>(object) : nullptr;
if (asSlotted != nullptr && asSlotted->MapPseudoSlot(CSlottedObject::Pseudoslot::POWER) >= 0)
{ {
CObject* power = dynamic_cast<CPoweredObject*>(object)->GetPower(); CObject *power = asSlotted->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::POWER);
if (power == nullptr) if (power == nullptr)
{ {
pVar->SetPointer(nullptr); pVar->SetPointer(nullptr);
@ -3702,9 +3706,9 @@ void CScriptFunctions::uObject(CBotVar* botThis, void* user)
// Updates the transported object's type. // Updates the transported object's type.
pVar = pVar->GetNext(); // "load" pVar = pVar->GetNext(); // "load"
if (object->Implements(ObjectInterfaceType::Carrier)) if (asSlotted != nullptr && asSlotted->MapPseudoSlot(CSlottedObject::Pseudoslot::CARRYING) >= 0)
{ {
CObject* cargo = dynamic_cast<CCarrierObject*>(object)->GetCargo(); CObject* cargo = asSlotted->GetSlotContainedObjectReq(CSlottedObject::Pseudoslot::CARRYING);
if (cargo == nullptr) if (cargo == nullptr)
{ {
pVar->SetPointer(nullptr); pVar->SetPointer(nullptr);

View File

@ -35,9 +35,8 @@
#include "object/old_object.h" #include "object/old_object.h"
#include "object/interface/carrier_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/programmable_object.h" #include "object/interface/programmable_object.h"
#include "object/interface/slotted_object.h"
#include "object/interface/task_executor_object.h" #include "object/interface/task_executor_object.h"
#include "object/motion/motion.h" #include "object/motion/motion.h"
@ -1373,7 +1372,7 @@ bool CObjectInterface::CreateInterface(bool bSelect)
pw->CreateButton(pos, dim, 10, EVENT_OBJECT_DESELECT); pw->CreateButton(pos, dim, 10, EVENT_OBJECT_DESELECT);
} }
if ( m_object->Implements(ObjectInterfaceType::Powered) ) // vehicle? if ( HasPowerCellSlot(m_object) ) // vehicle?
{ {
pos.x = ox+sx*14.5f; pos.x = ox+sx*14.5f;
pos.y = oy+sy*0; pos.y = oy+sy*0;
@ -1576,15 +1575,10 @@ void CObjectInterface::UpdateInterface(float rTime)
float energy = 0.0f; float energy = 0.0f;
float limit = 0.0f; float limit = 0.0f;
if (m_object->Implements(ObjectInterfaceType::Powered)) if (CPowerContainerObject* powerContainer = GetObjectPowerCell(m_object))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); energy = powerContainer->GetEnergyLevel();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) limit = powerContainer->GetEnergy();
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
energy = powerContainer->GetEnergyLevel();
limit = powerContainer->GetEnergy();
}
} }
icon = 0; // red/green icon = 0; // red/green
@ -1909,7 +1903,7 @@ void CObjectInterface::UpdateInterface()
bFly = bEnable; bFly = bEnable;
if ( bFly && (type == OBJECT_HUMAN || type == OBJECT_TECH) ) if ( bFly && (type == OBJECT_HUMAN || type == OBJECT_TECH) )
{ {
if (m_object->Implements(ObjectInterfaceType::Carrier) && dynamic_cast<CCarrierObject*>(m_object)->IsCarryingCargo()) if (dynamic_cast<CSlottedObject&>(*m_object).GetSlotContainedObjectOpt(CSlottedObject::Pseudoslot::CARRYING) != nullptr)
bFly = false; bFly = false;
} }
EnableInterface(pw, EVENT_OBJECT_GASUP, bFly && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_GASUP, bFly && m_main->CanPlayerInteract());