Finished coolant mod trial
parent
ad048ce60c
commit
8885f8476b
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;}
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ¶ms, 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue