Finished coolant mod trial

coolant-mod
immibis 2020-06-15 13:20:15 +02:00
parent ad048ce60c
commit 8885f8476b
13 changed files with 464 additions and 86 deletions

View File

@ -77,6 +77,8 @@ enum Error
ERR_RESEARCH_ENERGY = 321, //!< more energy
ERR_RESEARCH_TYPE = 322, //!< the wrong type of battery
ERR_RESEARCH_ALREADY = 323, //!< research already done
ERR_RESEARCH_NEED_COOLANT = 324, //!< need coolant
ERR_RESEARCH_MORE_COOLANT = 325, //!< need more coolant
ERR_ENERGY_NULL = 330, //!< no energy underground
ERR_ENERGY_LOW = 331, //!< not enough energy
ERR_ENERGY_EMPTY = 332, //!< lack of metal

View File

@ -616,6 +616,8 @@ void InitializeRestext()
stringsErr[ERR_RESEARCH_ENERGY] = TR("Not enough energy");
stringsErr[ERR_RESEARCH_TYPE] = TR("Inappropriate cell type");
stringsErr[ERR_RESEARCH_ALREADY]= TR("Research program already performed");
stringsErr[ERR_RESEARCH_NEED_COOLANT] = TR("No coolant cell");
stringsErr[ERR_RESEARCH_MORE_COOLANT] = TR("Not enough coolant");
stringsErr[ERR_ENERGY_NULL] = TR("No energy in the subsoil");
stringsErr[ERR_ENERGY_LOW] = TR("Not enough energy yet");
stringsErr[ERR_ENERGY_EMPTY] = TR("No titanium to transform");

View File

@ -33,6 +33,8 @@
#include "object/old_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/liquid_container_object.h"
#include "object/interface/slotted_object.h"
#include "sound/sound.h"
@ -127,6 +129,12 @@ Error CAutoResearch::StartAction(int param)
{
return ERR_RESEARCH_ENERGY;
}
CObject* coolantObj = dynamic_cast<CSlottedObject*>(m_object)->GetSlotContainedObject(0);
if (coolantObj == nullptr || !coolantObj->Implements(ObjectInterfaceType::LiquidContainer))
return ERR_RESEARCH_NEED_COOLANT;
CLiquidContainerObject *coolantAsLiq = dynamic_cast<CLiquidContainerObject*>(coolantObj);
if (coolantAsLiq->GetLiquidAmount() < 1.0f || coolantAsLiq->GetLiquidType() != LiquidType::WATER)
return ERR_RESEARCH_MORE_COOLANT;
float time = SEARCH_TIME;
if ( m_research == RESEARCH_TANK ) time *= 0.3f;
@ -221,7 +229,11 @@ bool CAutoResearch::EventProcess(const Event &event)
FireStopUpdate(m_progress, true); // flashes
if ( m_progress < 1.0f )
{
if ( m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer) ) // more battery?
CObject* coolantObj = dynamic_cast<CSlottedObject*>(m_object)->GetSlotContainedObject(0);
if ( m_object->GetPower() == nullptr || !m_object->GetPower()->Implements(ObjectInterfaceType::PowerContainer) // more battery?
|| coolantObj == nullptr || !coolantObj->Implements(ObjectInterfaceType::LiquidContainer) // coolant cell removed?
|| dynamic_cast<CLiquidContainerObject*>(coolantObj)->GetLiquidType() != LiquidType::WATER)
{
SetBusy(false);
UpdateInterface();
@ -233,6 +245,7 @@ bool CAutoResearch::EventProcess(const Event &event)
}
power = dynamic_cast<CPowerContainerObject*>(m_object->GetPower());
power->SetEnergyLevel(1.0f-m_progress);
dynamic_cast<CLiquidContainerObject*>(coolantObj)->SetLiquid(LiquidType::WATER, 1.0f - m_progress);
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{

View File

@ -0,0 +1,56 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2018, 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_interface_type.h"
#include <assert.h>
enum class LiquidType {
EMPTY,
WATER
};
/**
* \class CLiquidContainerObject
* \brief Interface for buckets
*/
class CLiquidContainerObject
{
protected:
LiquidType m_liquidType = LiquidType::EMPTY;
float m_liquidAmount = 0.0f;
public:
explicit CLiquidContainerObject(ObjectInterfaceTypes& types)
{
types[static_cast<int>(ObjectInterfaceType::LiquidContainer)] = true;
}
virtual ~CLiquidContainerObject()
{}
void SetLiquid(LiquidType type, float level) {
assert(level >= 0.0f && level <= 1.0f);
assert(type != LiquidType::EMPTY || level == 0.0f);
m_liquidType = (level == 0.0f ? LiquidType::EMPTY : type);
m_liquidAmount = level;
}
LiquidType GetLiquidType() const {return m_liquidType;}
float GetLiquidAmount() const {return m_liquidAmount;}
};

View File

@ -0,0 +1,53 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2018, 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_interface_type.h"
#include "math/vector.h"
class CObject;
/**
* \class CSlottedObject
* \brief Interface for objects that hold other objects
*/
class CSlottedObject
{
public:
explicit CSlottedObject(ObjectInterfaceTypes& types)
{
types[static_cast<int>(ObjectInterfaceType::Slotted)] = true;
}
virtual ~CSlottedObject()
{}
//! 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;
};

View File

@ -211,6 +211,7 @@ public:
//! \todo It will work like this for now but later I'd like to refactor this to something more manageable ~krzys_h
virtual bool IsBulletWall() { return false; }
protected:
//! Transform crash sphere by object's world matrix
virtual void TransformCrashSphere(Math::Sphere& crashSphere) = 0;

View File

@ -55,6 +55,7 @@ enum class ObjectInterfaceType
ShieldedAutoRegen, //!< shielded objects with auto shield regeneration
Old, //!< old objects, TODO: remove once no longer necessary
LiquidContainer, //!< liquid container
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)
};

View File

@ -18,6 +18,7 @@
*/
#include "object/subclass/base_building.h"
#include "object/interface/slotted_object.h"
#include "common/make_unique.h"
@ -47,6 +48,41 @@
#include "object/auto/autotower.h"
#include "object/auto/autovault.h"
class CResearchLab : public CBaseBuilding, public CSlottedObject {
public:
CResearchLab(int id)
: CBaseBuilding(id, OBJECT_RESEARCH)
, CSlottedObject(m_implementedInterfaces)
{
}
CObject *m_extraSlotObject = nullptr;
virtual int GetNumSlots() override {
return 1;
}
virtual Math::Vector GetSlotPosition(int slotNum) override {
assert(slotNum == 0);
return Math::Vector(-7.5f, 3.0f, 0.0f); // opposite the power cell slot
}
virtual float GetSlotAngle(int slotNum) override {
assert(slotNum == 0);
return Math::PI; // 180 degrees
}
virtual float GetSlotAcceptanceAngle(int slotNum) override {
assert(slotNum == 0);
return 45.0f*Math::PI/180.0f; // up to 45 degree offset is allowed, in either direction
}
virtual CObject *GetSlotContainedObject(int slotNum) override {
assert(slotNum == 0);
return m_extraSlotObject;
}
virtual void SetSlotContainedObject(int slotNum, CObject *object) override {
assert(slotNum == 0);
m_extraSlotObject = object;
}
};
CBaseBuilding::CBaseBuilding(int id, ObjectType type)
: COldObject(id)
@ -62,7 +98,7 @@ std::unique_ptr<CBaseBuilding> CBaseBuilding::Create(
Gfx::COldModelManager* modelManager,
Gfx::CEngine* engine)
{
auto obj = MakeUnique<CBaseBuilding>(params.id, params.type);
auto obj = (params.type == OBJECT_RESEARCH ? MakeUnique<CResearchLab>(params.id) : MakeUnique<CBaseBuilding>(params.id, params.type));
obj->SetTeam(params.team);
@ -272,7 +308,7 @@ std::unique_ptr<CBaseBuilding> CBaseBuilding::Create(
if ( params.type == OBJECT_RESEARCH )
{
modelManager->AddModelReference("search1.mod", false, rank, params.team);
modelManager->AddModelReference("search1_with_water.txt", false, rank, params.team);
obj->SetPosition(params.pos);
obj->SetRotationY(params.angle);
obj->SetFloorHeight(0.0f);

View File

@ -0,0 +1,112 @@
/*
* 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
*/
#include "object/object.h"
#include "object/old_object.h"
#include "object/interface/liquid_container_object.h"
#include "object/object_factory.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/oldmodelmanager.h"
#include "common/make_unique.h"
#include "level/parser/parserexceptions.h"
#include "level/parser/parserline.h"
#include "level/parser/parserparam.h"
#include "object/object_create_params.h"
#include <boost/lexical_cast.hpp>
class CBucket
: public COldObject
, public CLiquidContainerObject
{
LiquidType m_displayedLiquidType = LiquidType::EMPTY;
float m_displayedLiquidAmount = -100; // force initial update
public:
CBucket(int id)
: COldObject(id)
, CLiquidContainerObject(m_implementedInterfaces)
{
SetType(OBJECT_BUCKET);
m_implementedInterfaces[static_cast<int>(ObjectInterfaceType::Transportable)] = true;
}
bool EventProcess(const Event& event) override {
if (!COldObject::EventProcess(event))
return false;
if (event.type == EVENT_FRAME && (m_displayedLiquidType != m_liquidType || !Math::IsEqual(m_displayedLiquidAmount, m_liquidAmount, 0.003f))) {
UpdateTextureMapping();
m_displayedLiquidType = m_liquidType;
m_displayedLiquidAmount = m_liquidAmount;
}
return true;
}
private:
void UpdateTextureMapping() {
Gfx::Material mat;
mat.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f); // white
mat.ambient = Gfx::Color(0.5f, 0.5f, 0.5f);
int type = static_cast<int>(m_liquidType) - 1;
if(type > 0) type--; // don't use a texture slot for EMPTY liquid type, just reuse whatever liquid comes first
float vcoord = (type + 0.5f) / 128.0f;
// Y coordinate ranges from 0 to 2.
// If m_liquidAmount is 0, u coordinate ranges from 0 to 0.5.
// If m_liquidAmount is 1, u coordinate ranges from 0.5 to 1.
// In any case, v is a constant depending on the liquid type.
// The highest u coordinate needs to be at the lowest Y coordinate.
m_engine->ChangeTextureMapping(m_objectPart[0].object,
mat, Gfx::ENG_RSTATE_PART3, "objects/liquid.png", "",
Gfx::ENG_TEX_MAPPING_X,
0.0f, vcoord, -0.25f, 0.5f + 0.5f*m_liquidAmount);
}
};
std::unique_ptr<CObject> CreateObjectBucket(const ObjectCreateParams &params, Gfx::COldModelManager *modelManager, Gfx::CEngine *graphicsEngine)
{
std::unique_ptr<CBucket> newObj = MakeUnique<CBucket>(params.id);
int rootGraphObj = graphicsEngine->CreateObject();
graphicsEngine->SetObjectType(rootGraphObj, Gfx::ENG_OBJTYPE_FIX); // XXX: why is ENG_OBJTYPE_FIX used for movable objects? (this is the same as for powercells, titanium, etc)
newObj->SetObjectRank(0, rootGraphObj);
modelManager->AddModelCopy("bucket.txt", false, rootGraphObj);
newObj->SetPosition(params.pos);
newObj->SetRotationY(params.angle);
// standard settings for transportable objects
newObj->AddCrashSphere(CrashSphere(Math::Vector(0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f));
newObj->SetCameraCollisionSphere(Math::Sphere(Math::Vector(0.0f, 1.0f, 0.0f), 1.5f));
newObj->CreateShadowCircle(1.5f, 1.0f);
newObj->SetFloorHeight(0.0f);
newObj->FloorAdjust();
graphicsEngine->LoadAllTextures();
return newObj;
}

View File

@ -71,17 +71,23 @@ struct CAutoWaterPump : public CAuto
if (powerCell->Implements(ObjectInterfaceType::LiquidContainer)) {
// test code
CLiquidContainerObject *asPC = dynamic_cast<CLiquidContainerObject*>(powerCell);
float energy = asPC->GetLiquidAmount();
energy += (0.2f * event.rTime);
if(energy > 1.0f) energy = 0.0f;
asPC->SetLiquid(LiquidType::WATER, energy);
if (asPC->GetLiquidType() == LiquidType::WATER || asPC->GetLiquidType() == LiquidType::EMPTY) {
float water = asPC->GetLiquidAmount();
// animation
cycle = fmodf(cycle + event.rTime, 1.0f);
if (cycle < 0.5f)
m_object->SetPartPosition(1, Math::Vector(0.0f, 4.0f * cycle + 1.5f, 0.0f));
else
m_object->SetPartPosition(1, Math::Vector(0.0f, 4.0f - (4.0f * cycle) + 1.5f, 0.0f));
if (water < 1.0f)
{
// animation
cycle = fmodf(cycle + event.rTime, 1.0f);
if (cycle < 0.5f)
m_object->SetPartPosition(1, Math::Vector(0.0f, 4.0f * cycle + 1.5f, 0.0f));
else
m_object->SetPartPosition(1, Math::Vector(0.0f, 4.0f - (4.0f * cycle) + 1.5f, 0.0f));
}
water = water + (0.2f * event.rTime);
if(water > 1.0f) water = 1.0f;
asPC->SetLiquid(LiquidType::WATER, water);
}
}
}
}

View File

@ -1274,6 +1274,16 @@ bool CTaskGoto::GetHotPoint(CObject *pObj, Math::Vector &pos,
return true;
}
if ( type == OBJECT_WATERPUMP )
{
mat = pObj->GetWorldMatrix(0);
pos.x += 7.0f;
if ( bTake && distance != 0.0f ) suppl = 2.5f;
if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
pos = Transform(*mat, pos);
return true;
}
if ( type == OBJECT_ENERGY )
{
mat = pObj->GetWorldMatrix(0);

View File

@ -33,11 +33,14 @@
#include "object/interface/carrier_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h"
#include "object/interface/slotted_object.h"
#include "physics/physics.h"
#include "sound/sound.h"
const int INVALID_SLOT = -1;
const int ENERGY_CELL_SLOT = -2;
//?const float MARGIN_FRONT = 2.0f;
//?const float MARGIN_BACK = 2.0f;
@ -263,6 +266,16 @@ void CTaskManip::InitAngle()
}
}
static bool ObjectSlotOccupied(CObject *obj, int slotnum) {
if(slotnum == ENERGY_CELL_SLOT)
return ObjectHasPowerCell(obj);
else {
if (!obj->Implements(ObjectInterfaceType::Slotted))
return false;
return dynamic_cast<CSlottedObject*>(obj)->GetSlotContainedObject(slotnum) != nullptr;
}
}
// Assigns the goal was achieved.
Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
@ -393,7 +406,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if ( m_arm == TMA_FFRONT )
{
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 )
{
@ -403,7 +417,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
}
else if ( other != nullptr && oDist < fDist )
{
if (! ObjectHasPowerCell(other)) return ERR_MANIP_NIL;
if (! ObjectSlotOccupied(other, slotNum)) return ERR_MANIP_NIL;
m_targetPos = oPos;
m_angle = oAngle;
m_height = oHeight;
@ -436,8 +450,9 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
{
if ( m_arm == TMA_FFRONT )
{
other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight);
if (other != nullptr && !ObjectHasPowerCell(other))
int slotNum;
other = SearchOtherObject(true, oPos, oDist, oAngle, oHeight, slotNum);
if (other != nullptr && !ObjectSlotOccupied(other, slotNum))
{
m_targetPos = oPos;
m_angle = oAngle;
@ -868,8 +883,10 @@ CObject* CTaskManip::SearchTakeBackObject(bool bAdvance, Math::Vector &pos,
CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
float &distance, float &angle,
float &height)
float &height, int &slotNumOut)
{
slotNumOut = INVALID_SLOT;
Math::Matrix* mat;
float iAngle, oAngle, oLimit, aLimit, dLimit;
@ -901,59 +918,96 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
if ( pObj == m_object ) continue; // yourself?
ObjectType type = pObj->GetType();
if ( !pObj->Implements(ObjectInterfaceType::Powered) ) continue;
if ( pObj->Implements(ObjectInterfaceType::Powered) ) {
CObject* power = dynamic_cast<CPoweredObject*>(pObj)->GetPower();
if (power != nullptr)
{
if (power->GetLock()) continue;
if (power->GetScaleY() != 1.0f) continue;
}
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 if ( type == OBJECT_WATERPUMP )
{
oLimit = 3; //Math::PI doesn't work
}
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) )
CObject* power = dynamic_cast<CPoweredObject*>(pObj)->GetPower();
if (power == nullptr || (!power->GetLock() && power->GetScaleY() == 1.0f))
{
Math::Vector powerPos = dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition();
height = powerPos.y;
pos = oPos;
return pObj;
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 if ( type == OBJECT_WATERPUMP )
{
oLimit = 3; //Math::PI doesn't work
}
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) )
{
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();
height = powerPos.y;
pos = oPos;
slotNumOut = ENERGY_CELL_SLOT;
return pObj;
}
}
}
}
}
if (pObj->Implements(ObjectInterfaceType::Slotted)) {
CSlottedObject *obj = dynamic_cast<CSlottedObject*>(pObj);
int slotNum = obj->GetNumSlots();
for (int slot = 0; slot < slotNum; slot++) {
mat = pObj->GetWorldMatrix(0);
Math::Vector worldSlotPos = Transform(*mat, obj->GetSlotPosition(slot));
// TODO: check GetLock and GetScaleY, like for energy cell slot
CObject *objectInSlot = obj->GetSlotContainedObject(slot);
if (objectInSlot != nullptr && (objectInSlot->GetLock() || objectInSlot->GetScaleY() != 1.0f))
continue;
// 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 objectAngleOffsetLimit = obj->GetSlotAcceptanceAngle(slot);
float objectIdealAngle = 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;
}
}
}
}
}
}
@ -1094,19 +1148,36 @@ bool CTaskManip::TransporterTakeObject()
{
Math::Vector pos;
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;
assert(other->Implements(ObjectInterfaceType::Powered));
assert(slotNum != INVALID_SLOT);
CObject *cargo;
if (slotNum == ENERGY_CELL_SLOT) {
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable));
cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(nullptr);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CPoweredObject*>(other)->SetPower(nullptr);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
} else {
assert(other->Implements(ObjectInterfaceType::Slotted));
cargo = dynamic_cast<CSlottedObject*>(other)->GetSlotContainedObject(slotNum);
if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
dynamic_cast<CSlottedObject*>(other)->SetSlotContainedObject(slotNum, nullptr);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
}
pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
cargo->SetPosition(pos);
@ -1193,23 +1264,38 @@ bool CTaskManip::TransporterDeposeObject()
Math::Vector pos;
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;
assert(other->Implements(ObjectInterfaceType::Powered));
assert(slotNum != INVALID_SLOT);
if (slotNum == ENERGY_CELL_SLOT) {
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
if (cargo != nullptr) return false; // the other already has a battery?
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
if (cargo != nullptr) return false; // the other already has a battery?
} else {
assert(other->Implements(ObjectInterfaceType::Slotted));
CObject* cargo = dynamic_cast<CSlottedObject*>(other)->GetSlotContainedObject(slotNum);
if (cargo != nullptr) return false; // the other already has a battery?
}
cargo = m_object->GetCargo();
CObject *cargo = m_object->GetCargo();
if (cargo == nullptr) return false;
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(cargo);
if (slotNum == ENERGY_CELL_SLOT)
dynamic_cast<CPoweredObject*>(other)->SetPower(cargo);
else
dynamic_cast<CSlottedObject*>(other)->SetSlotContainedObject(slotNum, cargo);
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.
if (slotNum == ENERGY_CELL_SLOT)
cargo->SetPosition(dynamic_cast<CPoweredObject*>(other)->GetPowerPosition());
else
cargo->SetPosition(dynamic_cast<CSlottedObject*>(other)->GetSlotPosition(slotNum));
cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f);

View File

@ -73,7 +73,7 @@ protected:
CObject* SearchTakeUnderObject(Math::Vector &pos, float dLimit);
CObject* SearchTakeFrontObject(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 TransporterDeposeObject();
bool IsFreeDeposeObject(Math::Vector pos);