Added unit IDs, so Atlas can store references to units without just using pointers and without crashing.
This was SVN commit r3214.
This commit is contained in:
parent
bd2c1d73a3
commit
2eac4af3a4
@ -50,6 +50,7 @@ void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain_, CUnitManager
|
|||||||
g_EntityManager.deleteAll();
|
g_EntityManager.deleteAll();
|
||||||
// delete all remaining non-entity units
|
// delete all remaining non-entity units
|
||||||
pUnitMan->DeleteAll();
|
pUnitMan->DeleteAll();
|
||||||
|
g_UnitMan.SetNextID(0);
|
||||||
|
|
||||||
// unpack the data
|
// unpack the data
|
||||||
RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1250);
|
RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1250);
|
||||||
@ -437,7 +438,13 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
|||||||
if (! ent)
|
if (! ent)
|
||||||
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str());
|
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str());
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ent->SetPlayer(g_Game->GetPlayer(PlayerID));
|
ent->SetPlayer(g_Game->GetPlayer(PlayerID));
|
||||||
|
|
||||||
|
// TODO: save object IDs in the map file, and load them again,
|
||||||
|
// so that triggers have a persistent identifier for objects
|
||||||
|
ent->m_actor->SetID(g_UnitMan.GetNewID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completed_jobs++;
|
completed_jobs++;
|
||||||
@ -492,7 +499,7 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
|
|||||||
|
|
||||||
CUnit* unit = g_UnitMan.CreateUnit(ActorName, NULL);
|
CUnit* unit = g_UnitMan.CreateUnit(ActorName, NULL);
|
||||||
|
|
||||||
if (unit && unit->GetModel())
|
if (unit)
|
||||||
{
|
{
|
||||||
// Copied from CEntity::updateActorTransforms():
|
// Copied from CEntity::updateActorTransforms():
|
||||||
float s = sin(Orientation);
|
float s = sin(Orientation);
|
||||||
@ -503,6 +510,10 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
|
|||||||
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = Position.Z;
|
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = Position.Z;
|
||||||
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
||||||
unit->GetModel()->SetTransform(m);
|
unit->GetModel()->SetTransform(m);
|
||||||
|
|
||||||
|
// TODO: save object IDs in the map file, and load them again,
|
||||||
|
// so that triggers have a persistent identifier for objects
|
||||||
|
unit->SetID(g_UnitMan.GetNewID());
|
||||||
}
|
}
|
||||||
|
|
||||||
completed_jobs++;
|
completed_jobs++;
|
||||||
|
@ -15,10 +15,14 @@ class CUnit
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// constructor - unit invalid without a model and object
|
// constructor - unit invalid without a model and object
|
||||||
CUnit(CObjectEntry* object, CModel* model) : m_Object(object), m_Model(model), m_Entity(NULL) {
|
CUnit(CObjectEntry* object, CModel* model)
|
||||||
|
: m_Object(object), m_Model(model), m_Entity(NULL), m_ID(-1)
|
||||||
|
{
|
||||||
debug_assert(object && model);
|
debug_assert(object && model);
|
||||||
}
|
}
|
||||||
CUnit(CObjectEntry* object, CModel* model, CEntity* entity) : m_Object(object), m_Model(model), m_Entity(entity) {
|
CUnit(CObjectEntry* object, CModel* model, CEntity* entity)
|
||||||
|
: m_Object(object), m_Model(model), m_Entity(entity), m_ID(-1)
|
||||||
|
{
|
||||||
debug_assert(object && model);
|
debug_assert(object && model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,11 +30,11 @@ public:
|
|||||||
~CUnit();
|
~CUnit();
|
||||||
|
|
||||||
|
|
||||||
// get unit's template object
|
// get unit's template object; never NULL
|
||||||
CObjectEntry* GetObject() { return m_Object; }
|
CObjectEntry* GetObject() { return m_Object; }
|
||||||
// get unit's model data
|
// get unit's model data; never NULL
|
||||||
CModel* GetModel() { return m_Model; }
|
CModel* GetModel() { return m_Model; }
|
||||||
// get actor's entity
|
// get actor's entity; can be NULL
|
||||||
CEntity* GetEntity() { return m_Entity; }
|
CEntity* GetEntity() { return m_Entity; }
|
||||||
|
|
||||||
// Put here as it conveniently references both the model and the ObjectEntry
|
// Put here as it conveniently references both the model and the ObjectEntry
|
||||||
@ -49,6 +53,9 @@ public:
|
|||||||
// matchin 'name'.
|
// matchin 'name'.
|
||||||
bool IsPlayingAnimation(const CStr8& name);
|
bool IsPlayingAnimation(const CStr8& name);
|
||||||
|
|
||||||
|
int GetID() const { return m_ID; }
|
||||||
|
void SetID(int id) { m_ID = id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// object from which unit was created
|
// object from which unit was created
|
||||||
CObjectEntry* m_Object;
|
CObjectEntry* m_Object;
|
||||||
@ -56,6 +63,9 @@ private:
|
|||||||
CModel* m_Model;
|
CModel* m_Model;
|
||||||
// the entity that this actor represents, if any
|
// the entity that this actor represents, if any
|
||||||
CEntity* m_Entity;
|
CEntity* m_Entity;
|
||||||
|
// unique (per CGame) ID number for units created in the editor, as a
|
||||||
|
// permanent way of referencing them. -1 for non-editor units.
|
||||||
|
int m_ID;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,7 @@ extern CConsole* g_Console;
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// CUnitManager constructor
|
// CUnitManager constructor
|
||||||
CUnitManager::CUnitManager()
|
CUnitManager::CUnitManager()
|
||||||
|
: m_NextID(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,36 +78,36 @@ void CUnitManager::DeleteAll()
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// PickUnit: iterate through units testing given ray against bounds of each
|
// PickUnit: iterate through units testing given ray against bounds of each
|
||||||
// unit; return the closest unit, or null if everything missed
|
// unit; return the closest unit, or null if everything missed
|
||||||
CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) const
|
CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) const
|
||||||
{
|
{
|
||||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||||
|
|
||||||
// closest object found so far
|
// closest object found so far
|
||||||
CUnit* hit = 0;
|
CUnit* hit = 0;
|
||||||
// distance to closest object found so far
|
// distance to closest object found so far
|
||||||
float dist = 1.0e30f;
|
float dist = FLT_MAX;
|
||||||
// closest approach offset (easier to pick small stuff in forests than standard ScEd style selection)
|
// closest approach offset (easier to pick small stuff in forests than standard ScEd style selection)
|
||||||
float minrel = 1.0e30f;
|
float minrel = FLT_MAX;
|
||||||
|
|
||||||
for (uint i=0;i<m_Units.size();i++) {
|
for (uint i=0; i<m_Units.size(); i++) {
|
||||||
CUnit* unit=m_Units[i];
|
CUnit* unit = m_Units[i];
|
||||||
float tmin,tmax;
|
float tmin, tmax;
|
||||||
|
|
||||||
if (unit->GetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax)
|
if (unit->GetModel()->GetBounds().RayIntersect(origin, dir, tmin, tmax)
|
||||||
&& losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
|
&& losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
|
||||||
{
|
{
|
||||||
// Point of closest approach
|
// Point of closest approach
|
||||||
CVector3D obj;
|
CVector3D obj;
|
||||||
unit->GetModel()->GetBounds().GetCentre( obj );
|
unit->GetModel()->GetBounds().GetCentre(obj);
|
||||||
CVector3D delta = obj - origin;
|
CVector3D delta = obj - origin;
|
||||||
float distance = delta.Dot( dir );
|
float distance = delta.Dot(dir);
|
||||||
CVector3D closest = origin + dir * distance;
|
CVector3D closest = origin + dir * distance;
|
||||||
CVector3D offset = obj - closest;
|
CVector3D offset = obj - closest;
|
||||||
|
|
||||||
float rel = offset.GetLength();
|
float rel = offset.GetLength();
|
||||||
if (!hit || rel < minrel ) {
|
if (rel < minrel) {
|
||||||
hit=unit;
|
hit = unit;
|
||||||
dist=tmin;
|
dist = tmin;
|
||||||
minrel = rel;
|
minrel = rel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,3 +128,17 @@ CUnit* CUnitManager::CreateUnit(const CStr& actorName, CEntity* entity)
|
|||||||
AddUnit(unit);
|
AddUnit(unit);
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FindByID
|
||||||
|
CUnit* CUnitManager::FindByID(int id) const
|
||||||
|
{
|
||||||
|
if (id < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_Units.size(); ++i)
|
||||||
|
if (m_Units[i]->GetID() == id)
|
||||||
|
return m_Units[i];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -47,11 +47,19 @@ public:
|
|||||||
|
|
||||||
// iterate through units testing given ray against bounds of each unit;
|
// iterate through units testing given ray against bounds of each unit;
|
||||||
// return the closest unit, or null if everything missed
|
// return the closest unit, or null if everything missed
|
||||||
CUnit* PickUnit(const CVector3D& origin,const CVector3D& dir) const;
|
CUnit* PickUnit(const CVector3D& origin, const CVector3D& dir) const;
|
||||||
|
|
||||||
|
CUnit* FindByID(int id) const;
|
||||||
|
|
||||||
|
int GetNewID() { return m_NextID++; }
|
||||||
|
|
||||||
|
void SetNextID(int n) { m_NextID = n; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// list of all known units
|
// list of all known units
|
||||||
std::vector<CUnit*> m_Units;
|
std::vector<CUnit*> m_Units;
|
||||||
|
// next ID number to be assigned to a unit created in the editor
|
||||||
|
int m_NextID;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -391,6 +391,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
|||||||
// Toolbar:
|
// Toolbar:
|
||||||
|
|
||||||
ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar);
|
ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar);
|
||||||
|
// TODO: configurable small vs large icon images
|
||||||
// (button label; tooltip text; image; internal tool name)
|
// (button label; tooltip text; image; internal tool name)
|
||||||
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""));
|
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""));
|
||||||
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"));
|
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"));
|
||||||
|
@ -39,12 +39,15 @@ public:
|
|||||||
AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
|
AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
|
||||||
qry.Post();
|
qry.Post();
|
||||||
obj->m_Selection.clear();
|
obj->m_Selection.clear();
|
||||||
obj->m_Selection.push_back(qry.id);
|
if (AtlasMessage::ObjectIDIsValid(qry.id))
|
||||||
obj->m_dx = qry.offsetx;
|
{
|
||||||
obj->m_dy = qry.offsety;
|
obj->m_Selection.push_back(qry.id);
|
||||||
|
obj->m_dx = qry.offsetx;
|
||||||
|
obj->m_dy = qry.offsety;
|
||||||
|
SET_STATE(Dragging);
|
||||||
|
}
|
||||||
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
||||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||||
SET_STATE(Dragging);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())
|
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())
|
||||||
|
@ -8,6 +8,9 @@ namespace AtlasMessage
|
|||||||
// (Random note: Be careful not to give handler .cpp files the same name
|
// (Random note: Be careful not to give handler .cpp files the same name
|
||||||
// as any other file in the project, because it makes everything very confused)
|
// as any other file in the project, because it makes everything very confused)
|
||||||
|
|
||||||
|
// TODO: measure how long this static initialisation stuff takes, and if it's
|
||||||
|
// non-negligible then make it do as little work as possible if Atlas is not run
|
||||||
|
|
||||||
typedef void (*msgHandler)(IMessage*);
|
typedef void (*msgHandler)(IMessage*);
|
||||||
typedef std::map<std::string, msgHandler> msgHandlers;
|
typedef std::map<std::string, msgHandler> msgHandlers;
|
||||||
extern msgHandlers& GetMsgHandlers();
|
extern msgHandlers& GetMsgHandlers();
|
||||||
|
@ -39,11 +39,13 @@ void AtlasRenderSelection()
|
|||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
for (size_t i = 0; i < g_Selection.size(); ++i)
|
for (size_t i = 0; i < g_Selection.size(); ++i)
|
||||||
{
|
{
|
||||||
if (g_Selection[i])
|
CUnit* unit = g_UnitMan.FindByID(g_Selection[i]);
|
||||||
|
if (unit)
|
||||||
{
|
{
|
||||||
CUnit* unit = static_cast<CUnit*>(g_Selection[i]);
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
|
{
|
||||||
unit->GetEntity()->renderSelectionOutline();
|
unit->GetEntity()->renderSelectionOutline();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const CBound& bound = unit->GetModel()->GetBounds();
|
const CBound& bound = unit->GetModel()->GetBounds();
|
||||||
@ -118,7 +120,7 @@ MESSAGEHANDLER(EntityPreview)
|
|||||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->id);
|
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->id);
|
||||||
if (base) // (ignore errors)
|
if (base) // (ignore errors)
|
||||||
{
|
{
|
||||||
g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, 0);
|
g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, NULL);
|
||||||
// TODO: set player (for colour)
|
// TODO: set player (for colour)
|
||||||
// TODO: variations
|
// TODO: variations
|
||||||
}
|
}
|
||||||
@ -159,9 +161,9 @@ MESSAGEHANDLER(EntityPreview)
|
|||||||
|
|
||||||
BEGIN_COMMAND(CreateEntity)
|
BEGIN_COMMAND(CreateEntity)
|
||||||
|
|
||||||
HEntity m_Entity;
|
|
||||||
CVector3D m_Pos;
|
CVector3D m_Pos;
|
||||||
float m_Angle;
|
float m_Angle;
|
||||||
|
int m_ID;
|
||||||
|
|
||||||
void Do()
|
void Do()
|
||||||
{
|
{
|
||||||
@ -179,6 +181,8 @@ BEGIN_COMMAND(CreateEntity)
|
|||||||
m_Angle = d->angle;
|
m_Angle = d->angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_ID = g_UnitMan.GetNewID();
|
||||||
|
|
||||||
Redo();
|
Redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,18 +199,19 @@ BEGIN_COMMAND(CreateEntity)
|
|||||||
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", d->id.c_str());
|
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", d->id.c_str());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: player ID
|
// TODO: proper player ID
|
||||||
ent->SetPlayer(g_Game->GetLocalPlayer());
|
ent->SetPlayer(g_Game->GetLocalPlayer());
|
||||||
|
|
||||||
m_Entity = ent;
|
ent->m_actor->SetID(m_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Undo()
|
void Undo()
|
||||||
{
|
{
|
||||||
m_Entity->kill();
|
CUnit* unit = g_UnitMan.FindByID(m_ID);
|
||||||
m_Entity = HEntity();
|
if (unit && unit->GetEntity())
|
||||||
|
unit->GetEntity()->kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
END_COMMAND(CreateEntity)
|
END_COMMAND(CreateEntity)
|
||||||
@ -222,7 +227,10 @@ QUERYHANDLER(SelectObject)
|
|||||||
|
|
||||||
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
|
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
|
||||||
|
|
||||||
msg->id = static_cast<void*>(target);
|
if (target)
|
||||||
|
msg->id = target->GetID();
|
||||||
|
else
|
||||||
|
msg->id = -1;
|
||||||
|
|
||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
@ -246,10 +254,8 @@ BEGIN_COMMAND(MoveObject)
|
|||||||
|
|
||||||
void Do()
|
void Do()
|
||||||
{
|
{
|
||||||
if (! d->id)
|
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||||
return;
|
if (! unit) return;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
{
|
{
|
||||||
@ -268,10 +274,8 @@ BEGIN_COMMAND(MoveObject)
|
|||||||
|
|
||||||
void SetPos(CVector3D& pos)
|
void SetPos(CVector3D& pos)
|
||||||
{
|
{
|
||||||
if (! d->id)
|
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||||
return;
|
if (! unit) return;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
{
|
{
|
||||||
@ -311,10 +315,8 @@ BEGIN_COMMAND(RotateObject)
|
|||||||
|
|
||||||
void Do()
|
void Do()
|
||||||
{
|
{
|
||||||
if (! d->id)
|
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||||
return;
|
if (! unit) return;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
{
|
{
|
||||||
@ -365,10 +367,8 @@ BEGIN_COMMAND(RotateObject)
|
|||||||
|
|
||||||
void SetAngle(float angle, CMatrix3D& transform)
|
void SetAngle(float angle, CMatrix3D& transform)
|
||||||
{
|
{
|
||||||
if (! d->id)
|
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||||
return;
|
if (! unit) return;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
{
|
{
|
||||||
@ -402,29 +402,21 @@ END_COMMAND(RotateObject)
|
|||||||
|
|
||||||
BEGIN_COMMAND(DeleteObject)
|
BEGIN_COMMAND(DeleteObject)
|
||||||
|
|
||||||
bool m_ObjectAlive;
|
CUnit* m_UnitInLimbo;
|
||||||
|
|
||||||
void Construct()
|
void Construct()
|
||||||
{
|
{
|
||||||
m_ObjectAlive = true;
|
m_UnitInLimbo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Destruct()
|
void Destruct()
|
||||||
{
|
{
|
||||||
if (! m_ObjectAlive)
|
if (m_UnitInLimbo)
|
||||||
{
|
{
|
||||||
if (! d->id)
|
if (m_UnitInLimbo->GetEntity())
|
||||||
return;
|
m_UnitInLimbo->GetEntity()->kill();
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
|
||||||
unit->GetEntity()->kill();
|
|
||||||
else
|
else
|
||||||
{
|
delete m_UnitInLimbo;
|
||||||
g_UnitMan.RemoveUnit(unit);
|
|
||||||
delete unit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,33 +427,26 @@ BEGIN_COMMAND(DeleteObject)
|
|||||||
|
|
||||||
void Redo()
|
void Redo()
|
||||||
{
|
{
|
||||||
if (! d->id)
|
CUnit* unit = g_UnitMan.FindByID(d->id);
|
||||||
return;
|
if (! unit) return;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
|
||||||
|
|
||||||
if (unit->GetEntity())
|
if (unit->GetEntity())
|
||||||
|
{
|
||||||
// HACK: I don't know the proper way of undoably deleting entities...
|
// HACK: I don't know the proper way of undoably deleting entities...
|
||||||
unit->GetEntity()->m_destroyed = true;
|
unit->GetEntity()->m_destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
g_UnitMan.RemoveUnit(unit);
|
g_UnitMan.RemoveUnit(unit);
|
||||||
|
m_UnitInLimbo = unit;
|
||||||
m_ObjectAlive = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Undo()
|
void Undo()
|
||||||
{
|
{
|
||||||
if (! d->id)
|
if (m_UnitInLimbo->GetEntity())
|
||||||
return;
|
m_UnitInLimbo->GetEntity()->m_destroyed = false;
|
||||||
|
|
||||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
g_UnitMan.AddUnit(m_UnitInLimbo);
|
||||||
|
m_UnitInLimbo = NULL;
|
||||||
if (unit->GetEntity())
|
|
||||||
unit->GetEntity()->m_destroyed = false;
|
|
||||||
|
|
||||||
g_UnitMan.AddUnit(unit);
|
|
||||||
|
|
||||||
m_ObjectAlive = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
END_COMMAND(DeleteObject)
|
END_COMMAND(DeleteObject)
|
||||||
|
@ -167,7 +167,8 @@ COMMAND(PaintTerrain, MERGE,
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef void* ObjectID;
|
typedef int ObjectID;
|
||||||
|
inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); }
|
||||||
|
|
||||||
QUERY(SelectObject,
|
QUERY(SelectObject,
|
||||||
((Position, pos))
|
((Position, pos))
|
||||||
|
Loading…
Reference in New Issue
Block a user