1
0
forked from 0ad/0ad

# Delete a lot of obsolete simulation code.

This was SVN commit r7555.
This commit is contained in:
Ykkrosh 2010-05-20 18:09:23 +00:00
parent a78e6dbe26
commit 56bb858802
105 changed files with 381 additions and 11877 deletions

View File

@ -6,7 +6,7 @@ function setupSimTest(window)
function play(newSpeed)
{
if (state == 'inactive')
Atlas.Message.SimStateSave('default', true);
Atlas.Message.SimStateSave('default');
Atlas.Message.SimPlay(newSpeed);
state = 'playing';
speed = newSpeed;

View File

@ -432,8 +432,6 @@ function setup_all_libs ()
"ps/Network",
"ps/GameSetup",
"ps/XML",
"simulation",
"simulation/scripting",
"sound",
"scripting",
"maths",

View File

@ -42,19 +42,16 @@
#include "ps/Game.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Interact.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "scripting/ScriptableObject.h"
#include "simulation/Entity.h"
#include "simulation/EntityOrders.h"
#include "simulation/LOSManager.h"
#include "simulation/Projectile.h"
#include "simulation2/Simulation2.h"
float g_MaxZoomHeight=350.0f; //note: Max terrain height is this minus YMinOffset
@ -164,19 +161,13 @@ public:
CVector3D CameraDelta;
CVector3D CameraPivot;
CEntity* UnitView;
CModel* UnitViewProp;
CEntity* UnitAttach;
// CEntity* UnitAttach;
//float m_CameraZoom;
std::vector<CVector3D> CameraTargets;
// Accumulate zooming changes across frames for smoothness
float ZoomDelta;
// JS Interface
bool JSI_StartCustomSelection(JSContext *cx, uintN argc, jsval *argv);
bool JSI_EndCustomSelection(JSContext *cx, uintN argc, jsval *argv);
static void ScriptingInit();
};
@ -196,19 +187,10 @@ CGameView::CGameView(CGame *pGame):
m->ViewCamera.m_Orientation.Translate (100, 150, -100);
m->CullCamera = m->ViewCamera;
g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera);
m->UnitView=NULL;
m->UnitAttach=NULL;
}
CGameView::~CGameView()
{
if (!g_UseSimulation2)
{
g_Selection.ClearSelection();
g_Mouseover.Clear();
g_BuildingPlacer.Deactivate();
}
UnloadResources();
delete m;
@ -239,26 +221,16 @@ CCinemaManager* CGameView::GetCinema()
return &m->TrackManager;
};
/*
void CGameView::AttachToUnit(CEntity* target)
{
m->UnitAttach = target;
}
bool CGameView::IsAttached()
{
return (m->UnitAttach != NULL);
}
bool CGameView::IsUnitView()
{
return (m->UnitView != NULL);
}
*/
void CGameViewImpl::ScriptingInit()
{
AddMethod<bool, &CGameViewImpl::JSI_StartCustomSelection>("startCustomSelection", 0);
AddMethod<bool, &CGameViewImpl::JSI_EndCustomSelection>("endCustomSelection", 0);
AddProperty(L"culling", &CGameViewImpl::Culling);
AddProperty(L"lockCullCamera", &CGameViewImpl::LockCullCamera);
@ -392,79 +364,9 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
}
PROFILE_END( "submit terrain" );
if (g_UseSimulation2)
{
PROFILE_START( "submit sim components" );
m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
PROFILE_END( "submit sim components" );
return;
}
// Old simulation:
PROFILE_START( "submit models" );
CWorld* world = m->Game->GetWorld();
CUnitManager& unitMan = world->GetUnitManager();
CProjectileManager& pProjectileMan = world->GetProjectileManager();
CLOSManager* losMgr = world->GetLOSManager();
const std::vector<CUnit*>& units = unitMan.GetUnits();
for (size_t i=0;i<units.size();++i)
{
ogl_WarnIfError();
CEntity* ent = units[i]->GetEntity();
if( ent && !ent->m_visible )
continue;
int status = losMgr->GetUnitStatus(units[i], g_Game->GetLocalPlayer());
CModel& model = units[i]->GetModel();
model.ValidatePosition();
if (status != UNIT_HIDDEN &&
(!m->Culling || frustum.IsBoxVisible(CVector3D(0,0,0), model.GetBounds())))
{
if(units[i] != g_BuildingPlacer.m_actor)
{
CColor color;
if(status == UNIT_VISIBLE)
{
color = CColor(1.0f, 1.0f, 1.0f, 1.0f);
}
else // status == UNIT_REMEMBERED
{
color = CColor(0.7f, 0.7f, 0.7f, 1.0f);
}
model.SetShadingColor(color);
}
PROFILE( "submit models" );
c->SubmitRecursive(&model);
}
}
const std::list<CProjectile*>& projectiles = pProjectileMan.GetProjectiles();
std::list<CProjectile*>::const_iterator it = projectiles.begin();
for (; it != projectiles.end(); ++it)
{
CModel* model = (*it)->GetModel();
model->ValidatePosition();
const CBound& bound = model->GetBounds();
CVector3D centre;
bound.GetCentre(centre);
if ((!m->Culling || frustum.IsBoxVisible(CVector3D(0,0,0), bound))
&& losMgr->GetStatus(centre.X, centre.Z, g_Game->GetLocalPlayer()) & LOS_VISIBLE)
{
PROFILE( "submit projectiles" );
c->SubmitRecursive((*it)->GetModel());
}
}
PROFILE_END( "submit models" );
PROFILE_START( "submit sim components" );
m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
PROFILE_END( "submit sim components" );
}
@ -578,14 +480,7 @@ void CGameView::Update(float DeltaTime)
// in a CCmpWaterManager or some such thing (once such a thing exists)
g_Renderer.GetWaterManager()->m_WaterTexTimer += DeltaTime;
if (m->UnitView)
{
m->ViewCamera.m_Orientation.SetYRotation(m->UnitView->m_orientation.Y);
m->ViewCamera.m_Orientation.Translate(m->UnitViewProp->GetTransform().GetTranslation());
m->ViewCamera.UpdateFrustum();
return;
}
/*
if (m->UnitAttach)
{
CVector3D ToMove = m->UnitAttach->m_position - m->ViewCamera.GetFocus();
@ -594,6 +489,7 @@ void CGameView::Update(float DeltaTime)
m->ViewCamera.UpdateFrustum();
return;
}
*/
if (m->TrackManager.IsActive() && m->TrackManager.IsPlaying())
{
@ -818,19 +714,6 @@ void CGameView::Update(float DeltaTime)
m->ViewCamera.UpdateFrustum ();
}
void CGameView::ToUnitView(CEntity* target, CModel* prop)
{
if( !target )
{
//prevent previous zooming
m->ZoomDelta = 0.0f;
ResetCamera();
SetCameraTarget( m->UnitView->m_position );
}
m->UnitView = target;
m->UnitViewProp = prop;
}
void CGameView::PushCameraTarget( const CVector3D& target )
{
// Save the current position
@ -963,17 +846,3 @@ InReaction CGameView::HandleEvent(const SDL_Event_* ev)
return IN_PASS;
}
bool CGameViewImpl::JSI_StartCustomSelection(
JSContext* UNUSED(context), uintN UNUSED(argc), jsval* UNUSED(argv))
{
StartCustomSelection();
return true;
}
bool CGameViewImpl::JSI_EndCustomSelection(
JSContext* UNUSED(context), uintN UNUSED(argc), jsval* UNUSED(argv))
{
ResetInteraction();
return true;
}

View File

@ -32,7 +32,6 @@ class CObjectManager;
class CCamera;
class CCinemaManager;
class CVector3D;
class CEntity;
struct JSObject;
@ -94,13 +93,8 @@ public:
void SetCameraTarget( const CVector3D& target );
void PopCameraTarget();
//First person camera attachment (through the eyes of the unit)
void ToUnitView(CEntity* target, CModel* prop);
//Keep view the same but follow the unit
void AttachToUnit(CEntity* target);
bool IsAttached();
bool IsUnitView();
// void AttachToUnit(CEntity* target); // TODO: reimplement this for new sim system
CCamera *GetCamera();
CCinemaManager* GetCinema();

View File

@ -39,11 +39,6 @@
#include "ps/XML/Xeromyces.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
#include "simulation/TriggerManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPlayer.h"
@ -104,8 +99,6 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
// delete all existing entities
if (pSimulation2)
pSimulation2->ResetState();
if (pEntityMan)
pEntityMan->DeleteAll();
// delete all remaining non-entity units
if (pUnitMan)
@ -231,12 +224,6 @@ int CMapReader::ApplyData()
}
}
if (!g_UseSimulation2)
{
// Make units start out conforming correctly
pEntityMan->ConformAll();
}
if (file_format_version >= 4)
{
// copy over the lighting parameters
@ -296,7 +283,7 @@ private:
void ReadCamera(XMBElement parent);
void ReadCinema(XMBElement parent);
void ReadTriggers(XMBElement parent);
void ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group);
// void ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group);
int ReadEntities(XMBElement parent, double end_time);
int ReadOldEntities(XMBElement parent, double end_time);
int ReadNonEntities(XMBElement parent, double end_time);
@ -342,32 +329,29 @@ void CXMLReader::Init(const VfsPath& xml_filename)
for (int i = 0; i < nodes.Count; i++)
total_jobs += nodes.Item(i).GetChildNodes().Count;
if (g_UseSimulation2)
// Find the maximum entity ID, so we can safely allocate new IDs without conflicts
int max_uid = SYSTEM_ENTITY;
XMBElement ents = nodes.GetFirstNamedItem(xmb_file.GetElementID("Entities"));
XERO_ITER_EL(ents, ent)
{
// Find the maximum entity ID, so we can safely allocate new IDs without conflicts
utf16string uid = ent.GetAttributes().GetNamedItem(at_uid);
max_uid = std::max(max_uid, CStr(uid).ToInt());
}
int max_uid = SYSTEM_ENTITY;
// Initialise player data
XMBElement ents = nodes.GetFirstNamedItem(xmb_file.GetElementID("Entities"));
XERO_ITER_EL(ents, ent)
{
utf16string uid = ent.GetAttributes().GetNamedItem(at_uid);
max_uid = std::max(max_uid, CStr(uid).ToInt());
}
CmpPtr<ICmpPlayerManager> cmpPlayerMan(*m_MapReader.pSimulation2, SYSTEM_ENTITY);
debug_assert(!cmpPlayerMan.null());
// Initialise player data
CmpPtr<ICmpPlayerManager> cmpPlayerMan(*m_MapReader.pSimulation2, SYSTEM_ENTITY);
debug_assert(!cmpPlayerMan.null());
// TODO: this should be loaded from the XML instead
size_t numPlayers = 4;
for (size_t i = 0; i < numPlayers; ++i)
{
int uid = ++max_uid;
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(L"special/player", uid);
cmpPlayerMan->AddPlayer(ent);
}
// TODO: this should be loaded from the XML instead
size_t numPlayers = 4;
for (size_t i = 0; i < numPlayers; ++i)
{
int uid = ++max_uid;
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(L"special/player", uid);
cmpPlayerMan->AddPlayer(ent);
}
}
@ -727,12 +711,12 @@ void CXMLReader::ReadCinema(XMBElement parent)
void CXMLReader::ReadTriggers(XMBElement parent)
{
MapTriggerGroup rootGroup( L"Triggers", L"" );
if (m_MapReader.pTrigMan)
m_MapReader.pTrigMan->DestroyEngineTriggers();
ReadTriggerGroup(parent, rootGroup);
// MapTriggerGroup rootGroup( L"Triggers", L"" );
// if (m_MapReader.pTrigMan)
// m_MapReader.pTrigMan->DestroyEngineTriggers();
// ReadTriggerGroup(parent, rootGroup);
}
/*
void CXMLReader::ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group)
{
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
@ -894,6 +878,7 @@ void CXMLReader::ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group)
if (m_MapReader.pTrigMan)
m_MapReader.pTrigMan->AddGroup(mapGroup);
}
*/
int CXMLReader::ReadEntities(XMBElement parent, double end_time)
{
@ -1013,8 +998,6 @@ int CXMLReader::ReadOldEntities(XMBElement parent, double end_time)
debug_assert(entity.GetNodeName() == el_entity);
XMBAttributeList attrs = entity.GetAttributes();
utf16string uid = attrs.GetNamedItem(at_uid);
int unitId = uid.empty() ? -1 : CStr(uid).ToInt();
CStrW TemplateName;
int PlayerID = 0;
@ -1058,67 +1041,39 @@ int CXMLReader::ReadOldEntities(XMBElement parent, double end_time)
if (g_Game)
player = g_Game->GetPlayer(PlayerID);
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate(TemplateName, player);
if (! base)
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to load entity template '%ls'", TemplateName.c_str());
else
// The old version uses a flat entity naming system, so we need
// to translate it into the hierarchical filename
if (TemplateName.Find(L"flora") == 0 || TemplateName.Find(L"fauna") == 0 || TemplateName.Find(L"geology") == 0 || TemplateName.Find(L"special") == 0)
TemplateName = L"gaia/" + TemplateName;
else if (TemplateName.Find(L"cart") == 0 || TemplateName.Find(L"celt") == 0 || TemplateName.Find(L"hele") == 0 ||
TemplateName.Find(L"iber") == 0 || TemplateName.Find(L"pers") == 0 || TemplateName.Find(L"rome") == 0)
{
std::set<CStr> selections; // TODO: read from file
if (g_UseSimulation2)
{
// The old version uses a flat entity naming system, so we need
// to translate it into the hierarchical filename
if (TemplateName.Find(L"flora") == 0 || TemplateName.Find(L"fauna") == 0 || TemplateName.Find(L"geology") == 0 || TemplateName.Find(L"special") == 0)
TemplateName = L"gaia/" + TemplateName;
else if (TemplateName.Find(L"cart") == 0 || TemplateName.Find(L"celt") == 0 || TemplateName.Find(L"hele") == 0 ||
TemplateName.Find(L"iber") == 0 || TemplateName.Find(L"pers") == 0 || TemplateName.Find(L"rome") == 0)
{
if (TemplateName.Find(L"cavalry") == 5 || TemplateName.Find(L"hero") == 5 || TemplateName.Find(L"infantry") == 5 ||
TemplateName.Find(L"mechanical") == 5 || TemplateName.Find(L"ship") == 5 || TemplateName.Find(L"super") == 5 || TemplateName.Find(L"support") == 5)
TemplateName = L"units/" + TemplateName;
else
TemplateName = L"structures/" + TemplateName;
}
else if (TemplateName.Find(L"skeleton") == 0)
TemplateName = L"units/" + TemplateName;
else if (TemplateName.Find(L"camp") == 0 || TemplateName.Find(L"fence") == 0 || TemplateName.Find(L"temp") == 0)
TemplateName = L"other/" + TemplateName;
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(TemplateName);
if (ent != INVALID_ENTITY)
{
CmpPtr<ICmpPosition> cmpPos(*m_MapReader.pSimulation2, ent);
if (!cmpPos.null())
{
entity_pos_t x = entity_pos_t::FromFloat(Position.X);
entity_pos_t z = entity_pos_t::FromFloat(Position.Z);
cmpPos->JumpTo(x, z);
cmpPos->SetYRotation(entity_angle_t::FromFloat(Orientation));
}
CmpPtr<ICmpOwnership> cmpOwner(*m_MapReader.pSimulation2, ent);
if (!cmpOwner.null())
cmpOwner->SetOwner(PlayerID);
}
}
if (TemplateName.Find(L"cavalry") == 5 || TemplateName.Find(L"hero") == 5 || TemplateName.Find(L"infantry") == 5 ||
TemplateName.Find(L"mechanical") == 5 || TemplateName.Find(L"ship") == 5 || TemplateName.Find(L"super") == 5 || TemplateName.Find(L"support") == 5)
TemplateName = L"units/" + TemplateName;
else
TemplateName = L"structures/" + TemplateName;
}
else if (TemplateName.Find(L"skeleton") == 0)
TemplateName = L"units/" + TemplateName;
else if (TemplateName.Find(L"camp") == 0 || TemplateName.Find(L"fence") == 0 || TemplateName.Find(L"temp") == 0)
TemplateName = L"other/" + TemplateName;
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(TemplateName);
if (ent != INVALID_ENTITY)
{
CmpPtr<ICmpPosition> cmpPos(*m_MapReader.pSimulation2, ent);
if (!cmpPos.null())
{
HEntity ent = m_MapReader.pEntityMan->Create(base, Position, Orientation, selections);
if (! ent)
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to create entity of type '%ls'", TemplateName.c_str());
else
{
ent->m_actor->SetPlayerID(PlayerID);
m_MapReader.pEntityMan->AddEntityClassData(ent);
if (unitId < 0)
ent->m_actor->SetID(m_MapReader.pUnitMan->GetNewID());
else
ent->m_actor->SetID(unitId);
}
entity_pos_t x = entity_pos_t::FromFloat(Position.X);
entity_pos_t z = entity_pos_t::FromFloat(Position.Z);
cmpPos->JumpTo(x, z);
cmpPos->SetYRotation(entity_angle_t::FromFloat(Orientation));
}
CmpPtr<ICmpOwnership> cmpOwner(*m_MapReader.pSimulation2, ent);
if (!cmpOwner.null())
cmpOwner->SetOwner(PlayerID);
}
completed_jobs++;
@ -1174,35 +1129,16 @@ int CXMLReader::ReadNonEntities(XMBElement parent, double end_time)
std::set<CStr> selections; // TODO: read from file
if (g_UseSimulation2)
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(L"actor|" + ActorName);
if (ent != INVALID_ENTITY)
{
entity_id_t ent = m_MapReader.pSimulation2->AddEntity(L"actor|" + ActorName);
if (ent != INVALID_ENTITY)
CmpPtr<ICmpPosition> cmpPos(*m_MapReader.pSimulation2, ent);
if (!cmpPos.null())
{
CmpPtr<ICmpPosition> cmpPos(*m_MapReader.pSimulation2, ent);
if (!cmpPos.null())
{
entity_pos_t x = entity_pos_t::FromFloat(Position.X); // TODO: these should all be parsed as fixeds probably
entity_pos_t z = entity_pos_t::FromFloat(Position.Z);
cmpPos->JumpTo(x, z);
cmpPos->SetYRotation(entity_angle_t::FromFloat(Orientation));
}
}
}
else
{
CUnit* unit = m_MapReader.pUnitMan->CreateUnit(ActorName, NULL, selections);
if (unit)
{
CMatrix3D m;
m.SetYRotation(Orientation + (float)M_PI);
m.Translate(Position);
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(m_MapReader.pUnitMan->GetNewID());
entity_pos_t x = entity_pos_t::FromFloat(Position.X); // TODO: these should all be parsed as fixeds probably
entity_pos_t z = entity_pos_t::FromFloat(Position.Z);
cmpPos->JumpTo(x, z);
cmpPos->SetYRotation(entity_angle_t::FromFloat(Orientation));
}
}

View File

@ -41,17 +41,11 @@
#include "ps/XML/XMLWriter.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/TriggerManager.h"
#include "simulation/Entity.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpTemplateManager.h"
#define CURRENT_FILE_VERSION (g_UseSimulation2 ? FILE_VERSION : 4)
///////////////////////////////////////////////////////////////////////////////////////////////////
// CMapWriter constructor: nothing to do at the minute
CMapWriter::CMapWriter()
@ -65,7 +59,7 @@ void CMapWriter::SaveMap(const VfsPath& pathname, CTerrain* pTerrain,
CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema,
CSimulation2* pSimulation2)
{
CFilePacker packer(CURRENT_FILE_VERSION, "PSMP");
CFilePacker packer(FILE_VERSION, "PSMP");
// build necessary data
PackMap(packer, pTerrain);
@ -188,7 +182,7 @@ void CMapWriter::WriteXML(const VfsPath& filename,
{
XML_Element("Scenario");
XML_Attribute("version", (int)CURRENT_FILE_VERSION);
XML_Attribute("version", (int)FILE_VERSION);
if (pSimulation2 && !pSimulation2->GetStartupScript().empty())
{
@ -285,9 +279,6 @@ void CMapWriter::WriteXML(const VfsPath& filename,
}
}
const std::vector<CUnit*>& units = pUnitMan->GetUnits();
if (g_UseSimulation2)
{
XML_Element("Entities");
@ -336,75 +327,6 @@ void CMapWriter::WriteXML(const VfsPath& filename,
}
}
if (!g_UseSimulation2)
{
XML_Element("Entities");
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
{
CEntity* entity = (*unit)->GetEntity();
// Ignore objects that aren't entities
if (! entity)
continue;
XML_Element("Entity");
XML_Attribute("uid", (unsigned) (*unit)->GetID());
XML_Setting("Template", entity->m_base->m_Tag);
XML_Setting("Player", (unsigned) entity->GetPlayer()->GetPlayerID());
{
CVector3D position = entity->m_position;
XML_Element("Position");
XML_Attribute("x", position.X);
XML_Attribute("y", position.Y);
XML_Attribute("z", position.Z);
}
{
float angle = entity->m_orientation.Y;
XML_Element("Orientation");
XML_Attribute("angle", angle);
}
}
}
if (!g_UseSimulation2)
{
XML_Element("Nonentities");
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit) {
// Ignore objects that are entities
if ((*unit)->GetEntity())
continue;
XML_Element("Nonentity");
XML_Setting("Actor", (*unit)->GetObject().m_Base->m_Name);
{
CVector3D position = (*unit)->GetModel().GetTransform().GetTranslation();
XML_Element("Position");
XML_Attribute("x", position.X);
XML_Attribute("y", position.Y);
XML_Attribute("z", position.Z);
}
{
CVector3D orient = (*unit)->GetModel().GetTransform().GetIn();
float angle = atan2(-orient.X, -orient.Z);
XML_Element("Orientation");
XML_Attribute("angle", angle);
}
}
}
const std::map<CStrW, CCinemaPath>& paths = pCinema->GetAllPaths();
std::map<CStrW, CCinemaPath>::const_iterator it = paths.begin();
@ -453,39 +375,12 @@ void CMapWriter::WriteXML(const VfsPath& filename,
}
}
}
if (!g_UseSimulation2)
{
const std::list<MapTriggerGroup>& groups = g_TriggerManager.GetAllTriggerGroups();
std::list<MapTriggerGroup> rootChildren;
std::list<MapTriggerGroup>::const_iterator root = std::find( groups.begin(), groups.end(), L"Triggers" );
if ( root == groups.end() )
{
XML_Element("Triggers");
}
else
{
std::for_each(rootChildren.begin(), rootChildren.end(), CopyIfRootChild(rootChildren));
XML_Element("Triggers");
for ( std::list<MapTriggerGroup>::const_iterator it = rootChildren.begin();
it != rootChildren.end(); ++it )
{
WriteTriggerGroup(xml_file_, *it, groups);
}
for ( std::list<MapTrigger>::const_iterator it = root->triggers.begin();
it != root->triggers.end(); ++it )
{
WriteTrigger(xml_file_, *it);
}
}
}
}
if (! XML_StoreVFS(filename))
debug_assert(0); // failed to write map XML file
}
/*
void CMapWriter::WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group, const std::list<MapTriggerGroup>& groupList)
{
XML_Element("Group");
@ -593,6 +488,7 @@ void CMapWriter::WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigg
}
} //Effects' scope
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
// RewriteAllMaps

View File

@ -72,9 +72,9 @@ private:
void WriteXML(const VfsPath& pathname, CUnitManager* pUnitMan, WaterManager* pWaterMan,
SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera,
CCinemaManager* pCinema, CSimulation2* pSimulation2);
void WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group,
const std::list<MapTriggerGroup>& groupList);
void WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigger);
// void WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group,
// const std::list<MapTriggerGroup>& groupList);
// void WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigger);
};
#endif

View File

@ -27,8 +27,6 @@
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation/Entity.h"
#include "TerrainProperties.h"
#include "TextureEntry.h"
#include "TextureManager.h"
@ -107,26 +105,26 @@ bool CTerrain::IsOnMap(const CVector2D& v) const
return IsOnMap(v.x, v.y);
}
bool CTerrain::IsPassable(const CVector2D &loc/*tile space*/, HEntity entity) const
{
CMiniPatch *pTile = GetTile(loc.x, loc.y);
if(!pTile)
{
LOGWARNING(L"IsPassable: invalid coordinates %.1f %.1f\n", loc.x, loc.y);
return false;
}
if(!pTile->Tex1)
return false; // Invalid terrain type in the scenario file
CTextureEntry *pTexEntry = g_TexMan.FindTexture(pTile->Tex1);
CTerrainPropertiesPtr pProperties = pTexEntry->GetProperties();
if(!pProperties)
{
VfsPath texturePath = pTexEntry->GetTexturePath();
LOGWARNING(L"IsPassable: no properties loaded for %ls\n", texturePath.string().c_str());
return false;
}
return pProperties->IsPassable(entity);
}
//bool CTerrain::IsPassable(const CVector2D &loc/*tile space*/, HEntity entity) const
//{
// CMiniPatch *pTile = GetTile(loc.x, loc.y);
// if(!pTile)
// {
// LOGWARNING(L"IsPassable: invalid coordinates %.1f %.1f\n", loc.x, loc.y);
// return false;
// }
// if(!pTile->Tex1)
// return false; // Invalid terrain type in the scenario file
// CTextureEntry *pTexEntry = g_TexMan.FindTexture(pTile->Tex1);
// CTerrainPropertiesPtr pProperties = pTexEntry->GetProperties();
// if(!pProperties)
// {
// VfsPath texturePath = pTexEntry->GetTexturePath();
// LOGWARNING(L"IsPassable: no properties loaded for %ls\n", texturePath.string().c_str());
// return false;
// }
// return pProperties->IsPassable(entity);
//}
///////////////////////////////////////////////////////////////////////////////
// CalcPosition: calculate the world space position of the vertex at (i,j)
@ -301,27 +299,6 @@ float CTerrain::GetSlope(float x, float z) const
std::min(std::min(h00, h01), std::min(h10, h11));
}
CVector2D CTerrain::GetSlopeAngleFace( CEntity* entity ) const
{
CVector2D ret;
const float D = 0.1f; // Amount to look forward to calculate the slope
float x = entity->m_position.X;
float z = entity->m_position.Z;
// Get forward slope and use it as the x angle
CVector2D d = entity->m_ahead.Normalize() * D;
float dy = GetExactGroundLevel(x+d.x, z+d.y) - GetExactGroundLevel(x-d.x, z-d.y);
ret.x = atan2(dy, 2*D);
// Get sideways slope and use it as the y angle
CVector2D d2(-d.y, d.x);
float dy2 = GetExactGroundLevel(x+d2.x, z+d2.y) - GetExactGroundLevel(x-d2.x, z-d2.y);
ret.y = atan2(dy2, 2*D);
return ret;
}
float CTerrain::GetExactGroundLevel(float x, float z) const
{
// Clamp to size-2 so we can use the tiles (xi,zi)-(xi+1,zi+1)

View File

@ -22,15 +22,13 @@
#ifndef INCLUDED_TERRAIN
#define INCLUDED_TERRAIN
#include "ps/Vector2D.h"
#include "maths/Vector3D.h"
#include "maths/Fixed.h"
#include "graphics/SColor.h"
class HEntity;
class CEntity;
class CPatch;
class CMiniPatch;
class CVector2D;
class CFixedVector3D;
///////////////////////////////////////////////////////////////////////////////
@ -76,7 +74,7 @@ public:
bool IsOnMap(const CVector2D& v) const;
bool IsPassable(const CVector2D& tileSpaceLoc, HEntity entity) const;
// bool IsPassable(const CVector2D& tileSpaceLoc, HEntity entity) const;
float GetVertexGroundLevel(ssize_t i, ssize_t j) const;
float GetExactGroundLevel(float x, float z) const;
@ -84,8 +82,6 @@ public:
float GetExactGroundLevel(const CVector2D& v) const;
float GetSlope(float x, float z) const ;
//Find the slope of in X and Z axes depending on the way the entity is facing
CVector2D GetSlopeAngleFace(CEntity* entity) const;
// resize this terrain such that each side has given number of patches
void Resize(ssize_t size);

View File

@ -20,8 +20,6 @@
#include <vector>
#include <string>
#include "simulation/Entity.h"
#include "TerrainProperties.h"
#include "TextureManager.h"
#include "ps/Overlay.h"
@ -261,23 +259,13 @@ u32 CTerrainProperties::GetBaseColor()
return 0xFFFFFFFF;
}
const STerrainPassability &CTerrainProperties::GetPassability(HEntity entity)
{
std::vector<STerrainPassability>::iterator it=m_Passabilities.begin();
for (;it != m_Passabilities.end();++it)
{
if (entity->m_classes.IsMember(it->m_Type))
return *it;
}
return m_DefaultPassability;
}
bool CTerrainProperties::IsPassable(HEntity entity)
{
return GetPassability(entity).m_Passable;
}
double CTerrainProperties::GetSpeedFactor(HEntity entity)
{
return GetPassability(entity).m_SpeedFactor;
}
//const STerrainPassability &CTerrainProperties::GetPassability(HEntity entity)
//{
// std::vector<STerrainPassability>::iterator it=m_Passabilities.begin();
// for (;it != m_Passabilities.end();++it)
// {
// if (entity->m_classes.IsMember(it->m_Type))
// return *it;
// }
// return m_DefaultPassability;
//}

View File

@ -35,7 +35,6 @@ class CTerrainGroup;
class XMBElement;
class CXeromyces;
class CTerrainProperties;
class HEntity;
typedef shared_ptr<CTerrainProperties> CTerrainPropertiesPtr;
@ -101,9 +100,7 @@ public:
// The color value is in BGRA format
u32 GetBaseColor();
double GetSpeedFactor(HEntity entity);
bool IsPassable(HEntity entity);
const STerrainPassability &GetPassability(HEntity entity);
// const STerrainPassability &GetPassability(HEntity entity);
const GroupVector &GetGroups() const
{ return m_Groups; }

View File

@ -28,12 +28,10 @@
#include "ps/Game.h"
#include "ps/Player.h"
#include "simulation/Entity.h"
CUnit::CUnit(CObjectEntry* object, CEntity* entity, CObjectManager& objectManager,
const std::set<CStr>& actorSelections)
: m_Object(object), m_Model(object->m_Model->Clone()), m_Entity(entity),
: m_Object(object), m_Model(object->m_Model->Clone()),
m_ID(invalidUnitId), m_ActorSelections(actorSelections), m_PlayerID(invalidPlayerId),
m_ObjectManager(objectManager)
{
@ -181,9 +179,6 @@ void CUnit::SetPlayerID(size_t id)
{
m_PlayerID = id;
m_Model->SetPlayerID(m_PlayerID);
if (m_Entity)
m_Entity->SetPlayer(g_Game->GetPlayer(id));
}
void CUnit::SetEntitySelection(const CStr& selection)

View File

@ -62,7 +62,7 @@ public:
// get unit's model data
CModel& GetModel() const { return *m_Model; }
// get actor's entity; can be NULL
CEntity* GetEntity() const { return m_Entity; }
CEntity* GetEntity() const { return NULL; }
// Put here as it conveniently references both the model and the ObjectEntry
void ShowAmmunition();
@ -111,8 +111,6 @@ private:
CObjectEntry* m_Object;
// object model representation; never NULL
CModel* m_Model;
// the entity that this actor represents, if any
CEntity* m_Entity;
// player id of this unit (only read for graphical effects), or ~0 if unspecified
size_t m_PlayerID;

View File

@ -30,8 +30,6 @@
#include "ObjectEntry.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "simulation/Entity.h"
#include "simulation/LOSManager.h"
#include <algorithm>
@ -93,8 +91,6 @@ void CUnitManager::DeleteAll()
// unit; return the closest unit, or null if everything missed
CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir, bool entitiesOnly) const
{
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
// closest object found so far
CUnit* hit = 0;
// distance to closest object found so far
@ -106,14 +102,7 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir, boo
CUnit* unit = m_Units[i];
float tmin, tmax;
CEntity* ent = unit->GetEntity();
if( entitiesOnly && !ent )
continue;
if( ent && !ent->m_visible )
continue;
if (unit->GetModel().GetBounds().RayIntersect(origin, dir, tmin, tmax)
&& losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
if (unit->GetModel().GetBounds().RayIntersect(origin, dir, tmin, tmax))
{
// Point of closest approach
CVector3D obj;

View File

@ -35,17 +35,11 @@
#include "lib/sysdep/cpu.h"
#include "network/NetMessage.h"
#include "ps/Game.h"
#include "ps/Interact.h"
#include "ps/Player.h"
#include "ps/Profile.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "scripting/GameEvents.h"
#include "simulation/Entity.h"
#include "simulation/EntityTemplate.h"
#include "simulation/LOSManager.h"
#include "simulation/TerritoryManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpMinimap.h"
@ -108,14 +102,12 @@ void CMiniMap::HandleMessage(const SGUIMessage &Message)
}
case GUIM_MOUSE_ENTER:
{
if (!g_UseSimulation2)
g_Selection.m_mouseOverMM = true;
// g_Selection.m_mouseOverMM = true;
break;
}
case GUIM_MOUSE_LEAVE:
{
if (!g_UseSimulation2)
g_Selection.m_mouseOverMM = false;
// g_Selection.m_mouseOverMM = false;
m_Clicking = false;
break;
}
@ -182,11 +174,11 @@ void CMiniMap::SetCameraPos()
void CMiniMap::FireWorldClickEvent(int button, int clicks)
{
if (g_UseSimulation2)
return; // TODO: we ought to pass this through to the GUI system
// TODO: we ought to pass this through to the GUI system
//debug_printf(L"FireWorldClickEvent: button %d, clicks %d\n", button, clicks);
/*
CPos MousePos = GetMousePos();
CVector2D Destination;
//X and Z according to proportion of mouse position and minimap
@ -194,21 +186,10 @@ void CMiniMap::FireWorldClickEvent(int button, int clicks)
( (MousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth() );
Destination.y = CELL_SIZE * m_MapSize * ( (m_CachedActualSize.bottom - MousePos.y) /
m_CachedActualSize.GetHeight() );
*/
UNUSED2(button);
UNUSED2(clicks);
/*
g_JSGameEvents.FireWorldClick(
button,
clicks,
NMT_GOTO,
-1,
NMT_RUN,
-1,
NULL,
(int)Destination.x,
(int)Destination.y);
*/
}
// render view rect : John M. Mena
@ -304,9 +285,9 @@ void CMiniMap::Draw()
{
last_time = cur_time;
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
if(losMgr->m_LOSSetting != LOS_SETTING_ALL_VISIBLE)
RebuildLOSTexture();
// CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
// if(losMgr->m_LOSSetting != LOS_SETTING_ALL_VISIBLE)
// RebuildLOSTexture();
}
const float texCoordMax = ((float)m_MapSize - 1) / ((float)m_TextureSize);
@ -330,6 +311,7 @@ void CMiniMap::Draw()
glVertex3f(x, y2, z);
glEnd();
/* // TODO: reimplement with new sim system
// Shade territories by player
CTerritoryManager* territoryMgr = g_Game->GetWorld()->GetTerritoryManager();
std::vector<CTerritory*>& territories = territoryMgr->GetTerritories();
@ -380,6 +362,7 @@ void CMiniMap::Draw()
glLineWidth(1.0f);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
*/
// Draw the LOS quad in black, using alpha values from the LOS texture
g_Renderer.BindTexture(0, m_LOSTexture);
@ -417,67 +400,21 @@ void CMiniMap::Draw()
// (~70msec/frame on a GF4 rendering a thousand points)
glPointSize(3.f);
if (g_UseSimulation2)
float sx = m_scaleX / CELL_SIZE;
float sy = m_scaleY / CELL_SIZE;
CSimulation2* sim = g_Game->GetSimulation2();
const CSimulation2::InterfaceList& ents = sim->GetEntitiesWithInterface(IID_Minimap);
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
{
float sx = m_scaleX / CELL_SIZE;
float sy = m_scaleY / CELL_SIZE;
CSimulation2* sim = g_Game->GetSimulation2();
const CSimulation2::InterfaceList& ents = sim->GetEntitiesWithInterface(IID_Minimap);
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
MinimapUnitVertex v;
ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, v.x, v.y))
{
MinimapUnitVertex v;
ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, v.x, v.y))
{
v.a = 255;
v.x = x + v.x*sx;
v.y = y - v.y*sy;
vertexArray.push_back(v);
}
}
}
else
{
// Draw unit points
const std::vector<CUnit *> &units = m_UnitManager->GetUnits();
std::vector<CUnit *>::const_iterator iter = units.begin();
CUnit *unit = 0;
CVector2D pos;
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
for(; iter != units.end(); ++iter)
{
unit = (CUnit *)(*iter);
if(unit && unit->GetEntity() && losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
{
CEntity* entity = unit->GetEntity();
CStrW& type = entity->m_base->m_minimapType;
MinimapUnitVertex v;
if(type==L"Unit" || type==L"Structure" || type==L"Hero") {
// Use the player colour
const SPlayerColour& colour = entity->GetPlayer()->GetColour();
v.r = cpu_i32FromFloat(colour.r*255.f);
v.g = cpu_i32FromFloat(colour.g*255.f);
v.b = cpu_i32FromFloat(colour.b*255.f);
v.a = 255;
}
else {
CEntityTemplate* base = entity->m_base;
v.r = base->m_minimapR;
v.g = base->m_minimapG;
v.b = base->m_minimapB;
v.a = 255;
}
pos = GetMapSpaceCoords(entity->m_position);
v.x = x + pos.x;
v.y = y - pos.y;
vertexArray.push_back(v);
}
v.a = 255;
v.x = x + v.x*sx;
v.y = y - v.y*sy;
vertexArray.push_back(v);
}
}
@ -599,12 +536,10 @@ void CMiniMap::RebuildLOSTexture()
ssize_t w = m_MapSize - 1;
ssize_t h = m_MapSize - 1;
if (g_UseSimulation2)
{
memset(m_LOSData, 0, w*h);
}
else
{
memset(m_LOSData, 0, w*h);
// TODO: ought to do something like:
/*
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
CPlayer* player = g_Game->GetLocalPlayer();
@ -622,7 +557,7 @@ void CMiniMap::RebuildLOSTexture()
*dataPtr++ = 0;
}
}
}
*/
// Upload the texture
g_Renderer.BindTexture(0, m_LOSTexture);

View File

@ -65,14 +65,14 @@ void PopGuiPage(void* UNUSED(cbdata))
bool IsNewSimulation(void* UNUSED(cbdata))
{
return g_UseSimulation2;
return true; // XXX: delete this function
}
CScriptVal GuiInterfaceCall(void* cbdata, std::wstring name, CScriptVal data)
{
CGUIManager* guiManager = static_cast<CGUIManager*> (cbdata);
if (!g_UseSimulation2 || !g_Game)
if (!g_Game)
return JSVAL_VOID;
CSimulation2* sim = g_Game->GetSimulation2();
debug_assert(sim);
@ -94,7 +94,7 @@ void PostNetworkCommand(void* cbdata, CScriptVal cmd)
{
CGUIManager* guiManager = static_cast<CGUIManager*> (cbdata);
if (!g_UseSimulation2 || !g_Game)
if (!g_Game)
return;
CSimulation2* sim = g_Game->GetSimulation2();
debug_assert(sim);

View File

@ -53,14 +53,13 @@ that of Atlas depending on commandline parameters.
#include "ps/Game.h"
#include "ps/Hotkey.h"
#include "ps/Globals.h"
#include "ps/Interact.h"
#include "ps/XML/Xeromyces.h"
#include "network/NetClient.h"
#include "network/NetServer.h"
#include "network/NetSession.h"
#include "graphics/Camera.h"
#include "graphics/GameView.h"
#include "simulation/Scheduler.h"
#include "scripting/Scheduler.h"
#include "simulation2/Simulation2.h"
#include "sound/CMusicPlayer.h"
#include "gui/GUIManager.h"
@ -285,16 +284,6 @@ static void Frame()
g_Game->GetView()->Update(float(TimeSinceLastFrame));
PROFILE_END( "camera update" );
if (!g_UseSimulation2)
{
PROFILE_START( "selection and interaction ui" );
// TODO Where does GameView end and other things begin?
g_Mouseover.Update( TimeSinceLastFrame );
g_Selection.Update();
g_BuildingPlacer.Update( TimeSinceLastFrame );
PROFILE_END( "selection and interaction ui" );
}
PROFILE_START( "sound update" );
CCamera* camera = g_Game->GetView()->GetCamera();
CMatrix3D& orientation = camera->m_Orientation;

View File

@ -30,7 +30,7 @@
#include "NetSession.h"
#include "NetTurnManager.h"
#include "ps/CStr.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptObject.h"
#include "scripting/ScriptableObject.h"
#include "ps/scripting/JSMap.h"

View File

@ -30,7 +30,6 @@
#include "ps/CStr.h"
#include "scripting/JSSerialization.h"
#include "scriptinterface/ScriptVal.h"
#include "simulation/EntityHandles.h"
// DEFINES
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'

View File

@ -35,7 +35,7 @@
#include "ps/scripting/JSMap.h"
#include "ps/Player.h"
#include "ps/Game.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptObject.h"
#include <map>
#include <vector>

View File

@ -34,7 +34,6 @@
#include "ps/Filesystem.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Interact.h"
#include "ps/Pyrogenesis.h"
#include "scripting/ScriptingHost.h"
#include "scripting/ScriptableComplex.inl"

View File

@ -36,9 +36,6 @@
#include "ps/Loader.h"
#include "ps/Profile.h"
#include "ps/World.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
#include "simulation/Simulation.h"
#include "simulation2/Simulation2.h"
#include "gui/GUIManager.h"
@ -70,8 +67,7 @@ CGame *g_Game=NULL;
**/
CGame::CGame():
m_World(new CWorld(this)),
m_Simulation(g_UseSimulation2 ? NULL : new CSimulation(this)),
m_Simulation2(g_UseSimulation2 ? new CSimulation2(&m_World->GetUnitManager(), m_World->GetTerrain()) : NULL),
m_Simulation2(new CSimulation2(&m_World->GetUnitManager(), m_World->GetTerrain())),
m_GameView(new CGameView(this)),
m_pLocalPlayer(NULL),
m_GameStarted(false),
@ -82,16 +78,13 @@ CGame::CGame():
// been initialised, so do it here rather than via the initialisers above.
m_World->GetUnitManager().SetObjectManager(m_GameView->GetObjectManager());
if (g_UseSimulation2)
{
m_TurnManager = new CNetLocalTurnManager(*m_Simulation2); // this will get replaced if we're a net server/client
m_TurnManager = new CNetLocalTurnManager(*m_Simulation2); // this will get replaced if we're a net server/client
m_Simulation2->LoadDefaultScripts();
m_Simulation2->ResetState();
m_Simulation2->LoadDefaultScripts();
m_Simulation2->ResetState();
CScriptVal initData; // TODO: ought to get this from the GUI, somehow
m_Simulation2->InitGame(initData);
}
CScriptVal initData; // TODO: ought to get this from the GUI, somehow
m_Simulation2->InitGame(initData);
}
#if MSC_VERSION
@ -110,7 +103,6 @@ CGame::~CGame()
delete m_TurnManager;
delete m_GameView;
delete m_Simulation2;
delete m_Simulation;
delete m_World;
}
@ -141,8 +133,6 @@ PSRETURN CGame::RegisterInit(CGameAttributes* pAttribs)
// some point to be stored in the world object?
m_GameView->RegisterInit(pAttribs);
m_World->RegisterInit(pAttribs);
if (!g_UseSimulation2)
m_Simulation->RegisterInit(pAttribs);
LDR_EndRegistering();
return 0;
}
@ -249,38 +239,17 @@ bool CGame::Update(double deltaTime, bool doInterpolate)
bool ok = true;
if (deltaTime)
{
if (g_UseSimulation2)
{
PROFILE("update");
if (m_TurnManager->Update(deltaTime))
g_GUI->SendEventToAll("SimulationUpdate");
}
else
{
ok = m_Simulation->Update(deltaTime);
}
PROFILE("update");
if (m_TurnManager->Update(deltaTime))
g_GUI->SendEventToAll("SimulationUpdate");
}
if (doInterpolate)
{
PROFILE("interpolate");
if (g_UseSimulation2)
m_TurnManager->Interpolate(deltaTime);
else
m_Simulation->Interpolate(deltaTime);
m_TurnManager->Interpolate(deltaTime);
}
// TODO Detect game over and bring up the summary screen or something
// ^ Quick game over hack is implemented, no summary screen however
/*if (m_World->GetEntityManager().GetDeath())
{
UpdateGameStatus();
if (GameStatus != 0)
EndGame();
}
//reset death event flag
m_World->GetEntityManager().SetDeath(false);*/
return ok;
}

View File

@ -28,10 +28,8 @@
#include <vector>
class CWorld;
class CSimulation;
class CSimulation2;
class CGameView;
class CSimulation;
class CPlayer;
class CGameAttributes;
class CNetTurnManager;
@ -55,10 +53,6 @@ class CGame
* pointer to the CWorld object representing the game world.
**/
CWorld *m_World;
/**
* pointer to the CSimulation object operating on the game world.
**/
CSimulation *m_Simulation;
/**
* pointer to the CSimulation2 object operating on the game world.
**/
@ -189,13 +183,6 @@ public:
**/
inline CGameView *GetView()
{ return m_GameView; }
/**
* Get the pointer to the simulation object.
*
* @return CSimulation * the value of m_Simulation.
**/
inline CSimulation *GetSimulation()
{ return m_Simulation; }
/**
* Get the pointer to the simulation2 object.
*

View File

@ -39,13 +39,13 @@
#include "ps/Game.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Interact.h"
#include "ps/Loader.h"
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "ps/StringConvert.h"
#include "ps/Util.h"
#include "ps/World.h"
#include "ps/i18n.h"
#include "graphics/CinemaTrack.h"
@ -61,30 +61,21 @@
#include "maths/MathUtil.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/Scheduler.h"
#include "simulation2/Simulation2.h"
#include "scripting/ScriptableComplex.inl"
#include "scripting/ScriptingHost.h"
#include "scripting/ScriptGlue.h"
#include "scripting/DOMEvent.h"
#include "scripting/GameEvents.h"
#include "scripting/ScriptableComplex.h"
#include "scripting/Scheduler.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "graphics/scripting/JSInterface_Camera.h"
#include "graphics/scripting/JSInterface_LightEnv.h"
#include "ps/scripting/JSInterface_Selection.h"
#include "ps/scripting/JSInterface_Console.h"
#include "ps/scripting/JSCollection.h"
#include "simulation/scripting/SimulationScriptInit.h"
#include "gui/GUI.h"
#include "gui/GUIManager.h"
@ -240,88 +231,10 @@ void Render()
ogl_WarnIfError();
if (g_Game && g_Game->IsGameStarted() && g_UseSimulation2)
if (g_Game && g_Game->IsGameStarted())
{
g_Game->GetView()->Render();
}
else if (g_Game && g_Game->IsGameStarted() && !g_UseSimulation2)
{
g_Game->GetView()->Render();
glPushAttrib( GL_ENABLE_BIT );
glDisable( GL_LIGHTING );
glDisable( GL_TEXTURE_2D );
glDisable( GL_DEPTH_TEST );
if( g_EntGraph )
{
PROFILE( "render entity overlays" );
glColor3f( 1.0f, 0.0f, 1.0f );
g_EntityManager.RenderAll(); // <-- collision outlines, pathing routes
}
glEnable( GL_DEPTH_TEST );
PROFILE_START( "render entity outlines" );
g_Mouseover.RenderSelectionOutlines();
g_Selection.RenderSelectionOutlines();
PROFILE_END( "render entity outlines" );
PROFILE_START( "render entity auras" );
g_Mouseover.RenderAuras();
g_Selection.RenderAuras();
PROFILE_END( "render entity auras" );
glDisable(GL_DEPTH_TEST);
PROFILE_START( "render entity bars" );
pglActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
/*glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.0f, 1000.f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();*/
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
g_Mouseover.RenderBars();
g_Selection.RenderBars();
glDisable(GL_BLEND);
/*glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);*/
PROFILE_END( "render entity bars" );
glPopAttrib();
glMatrixMode(GL_MODELVIEW);
// Depth test is now enabled
PROFILE_START( "render rally points" );
g_Selection.RenderRallyPoints();
g_Mouseover.RenderRallyPoints();
PROFILE_END( "render rally points" );
PROFILE_START( "render cinematic splines" );
//Sets/resets renderering properties itself
g_Game->GetView()->GetCinema()->DrawSpline();
PROFILE_END( "render cinematic splines" );
}
ogl_WarnIfError();
@ -390,17 +303,8 @@ void Render()
ogl_WarnIfError();
if (g_Game && g_Game->IsGameStarted() && !g_UseSimulation2)
{
PROFILE( "render selection overlays" );
g_Mouseover.RenderOverlays();
g_Selection.RenderOverlays();
}
ogl_WarnIfError();
// Draw the cursor (or set the Windows cursor, on Windows)
CStrW cursorName = (!g_UseSimulation2 && g_BuildingPlacer.m_active) ? L"action-build" : g_CursorName;
CStrW cursorName = g_CursorName;
if (cursorName.empty())
cursor_draw(NULL, g_mouse_x, g_mouse_y);
else
@ -439,10 +343,6 @@ static void RegisterJavascriptInterfaces()
// scripting
SColour::ScriptingInit();
CScriptEvent::ScriptingInit();
// call CJSComplexPropertyAccessor's ScriptingInit. doesn't really
// matter which <T> we use, but we know CJSPropertyAccessor<T> is
// already being compiled for T = CEntity.
ScriptableComplex_InitComplexPropertyAccessor<CEntity>();
// ps
JSI_Console::init();
@ -457,9 +357,6 @@ static void RegisterJavascriptInterfaces()
CNetSession::ScriptingInit();
CServerPlayer::ScriptingInit();
// simulation
SimulationScriptInit();
// GUI
CGUI::ScriptingInit();
@ -487,8 +384,6 @@ static void InitScripting()
REG_JS_CONSTANT(SDL_BUTTON_WHEELUP);
REG_JS_CONSTANT(SDL_BUTTON_WHEELDOWN);
#undef REG_JS_CONSTANT
new CGameEvents;
}
@ -622,8 +517,6 @@ static void InitInput()
// processed.
in_add_handler(game_view_handler);
in_add_handler(InteractInputHandler);
in_add_handler(conInputHandler);
in_add_handler(CProfileViewer::InputThunk);
@ -729,28 +622,9 @@ void Shutdown(int flags)
delete &g_Scheduler;
TIMER_END(L"shutdown Scheduler");
delete &g_JSGameEvents;
if (! (flags & INIT_NO_SIM))
{
if (g_UseSimulation2)
{
delete &g_GameAttributes;
delete &g_EntityTemplateCollection;
}
else
{
TIMER_BEGIN(L"shutdown mouse stuff");
delete &g_Mouseover;
delete &g_Selection;
delete &g_BuildingPlacer;
TIMER_END(L"shutdown mouse stuff");
TIMER_BEGIN(L"shutdown game scripting stuff");
delete &g_GameAttributes;
SimulationShutdown();
TIMER_END(L"shutdown game scripting stuff");
}
delete &g_GameAttributes;
}
// destroy actor related stuff
@ -991,24 +865,7 @@ void Init(const CmdLineArgs& args, int flags)
if (! (flags & INIT_NO_SIM))
{
// This needs to be done after the renderer has loaded all its actors...
if (g_UseSimulation2)
{
new CEntityTemplateCollection; // this is just needed for loading old maps
new CGameAttributes;
}
else
{
SimulationInit();
{
TIMER(L"Init_miscgamesection");
new CSelectedEntities;
new CMouseoverEntities;
new CBuildingPlacer;
new CGameAttributes;
}
}
new CGameAttributes;
// Register a few Game/Network JS globals
g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes.GetScript()));
@ -1152,7 +1009,7 @@ static bool Autostart(const CmdLineArgs& args)
ret = g_Game->ReallyStartGame();
debug_assert(ret == PSRETURN_OK);
InitPs(true, g_UseSimulation2 ? L"page_session_new.xml" : L"page_session.xml");
InitPs(true, L"page_session_new.xml");
}
return true;

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// Interact.h
//
// Manages main-screen interaction (screen->worldspace mapping, unit selection, ordering, etc.)
// and the hotkey message processor.
// Does this belong in GUI?
#ifndef INCLUDED_INTERACT
#define INCLUDED_INTERACT
#include <vector>
#include <map>
#include "CStr.h"
#include "Singleton.h"
#include "simulation/EntityHandles.h"
#include "ps/Vector2D.h"
#include "lib/input.h"
#include "lib/res/handle.h"
class CVector3D;
class CUnit;
class CEntityTemplate;
class CBoundingObject;
#define MAX_BOOKMARKS 10
#define MAX_GROUPS 20
// CSelectedEntities: the singleton containing entities currently selected on the local machine.
// (including group allocations on the local machine)
struct CSelectedEntities : public Singleton<CSelectedEntities>
{
CSelectedEntities()
{
ClearSelection();
m_group = -1;
m_group_highlight = -1;
m_defaultCommand = -1;
m_defaultAction = -1;
m_secondaryCommand = -1;
m_secondaryAction = -1;
m_selectionChanged = true;
m_mouseOverMM = false;
LoadUnitUiTextures();
}
~CSelectedEntities()
{
DestroyUnitUiTextures();
}
std::vector<HEntity> m_selected;
std::vector<HEntity> m_groups[MAX_GROUPS];
i8 m_group, m_group_highlight;
bool m_selectionChanged;
bool m_mouseOverMM;
int m_defaultCommand;
int m_defaultAction;
int m_secondaryCommand;
int m_secondaryAction;
void AddSelection( HEntity entity );
void RemoveSelection( HEntity entity );
void SetSelection( HEntity entity );
void ClearSelection();
void RemoveAll( HEntity entity );
bool IsSelected( HEntity entity );
CVector3D GetSelectionPosition();
void AddToGroup( i8 groupid, HEntity entity );
void SaveGroup( i8 groupid );
void LoadGroup( i8 groupid );
void AddGroup( i8 groupid );
void ChangeGroup( HEntity entity, i8 groupid );
void HighlightGroup( i8 groupid );
void HighlightNone();
int GetGroupCount( i8 groupid );
CVector3D GetGroupPosition( i8 groupid );
void Update();
void RenderSelectionOutlines();
void RenderOverlays();
void RenderAuras();
void RenderRallyPoints();
void RenderBars();
void RenderHealthBars();
void RenderStaminaBars();
void RenderRanks();
void RenderBarBorders();
void DestroyUnitUiTextures();
int LoadUnitUiTextures();
typedef std::map<CStrW, Handle> MapFilenameToHandle;
MapFilenameToHandle m_unitUITextures;
};
// CMouseoverEntities: the singleton containing entities the mouse is currently hovering over or bandboxing
// ( for mouseover selection outlines )
struct SMouseoverFader
{
HEntity entity;
float fade;
bool isActive;
SMouseoverFader( HEntity _entity, float _fade = 0.0f, bool _active = true ) : entity( _entity ), fade( _fade ), isActive( _active ) {}
};
struct CMouseoverEntities : public Singleton<CMouseoverEntities>
{
float m_fadeinrate;
float m_fadeoutrate;
float m_fademaximum;
CVector2D m_worldposition;
HEntity m_target;
HEntity m_lastTarget;
bool m_targetChanged;
bool m_bandbox, m_viewall;
u16 m_x1, m_y1, m_x2, m_y2;
CMouseoverEntities()
{
m_bandbox = false;
m_viewall = false;
m_fadeinrate = 1.0f;
m_fadeoutrate = 2.0f;
m_fademaximum = 0.5f;
m_mouseover.clear();
m_targetChanged = true;
}
std::vector<SMouseoverFader> m_mouseover;
void Update( float timestep );
void AddSelection();
void RemoveSelection();
void SetSelection();
void ExpandAcrossScreen();
void ExpandAcrossWorld();
void RenderSelectionOutlines();
void RenderOverlays();
void RenderRallyPoints();
void RenderAuras();
void RenderBars();
void RenderHealthBars();
void RenderStaminaBars();
void RenderRanks();
void RenderBarBorders();
bool IsBandbox() { return( m_bandbox ); }
void StartBandbox( u16 x, u16 y );
void StopBandbox();
void Clear() { m_mouseover.clear(); }
};
struct CBuildingPlacer : public Singleton<CBuildingPlacer>
{
CBuildingPlacer()
{
m_active = false;
m_actor = 0;
m_bounds = 0;
}
CStrW m_templateName;
CEntityTemplate* m_template;
bool m_active;
bool m_clicked;
bool m_dragged;
float m_angle;
bool m_valid;
float m_timeSinceClick;
float m_totalTime;
CVector3D clickPos;
CUnit* m_actor;
CBoundingObject* m_bounds;
bool Activate( CStrW& templateName );
void Deactivate();
void MousePressed();
void MouseReleased();
void Update( float timeStep );
void CheckValidLocation( CVector3D pos, bool onSocket );
bool IsWithinLimit( CVector3D pos );
};
bool IsMouseoverType( CEntity* ev, void* userdata );
bool IsOnScreen( CEntity* ev, void* userdata );
void StartCustomSelection();
void ResetInteraction();
InReaction InteractInputHandler( const SDL_Event_* ev );
#define g_Selection CSelectedEntities::GetSingleton()
#define g_Mouseover CMouseoverEntities::GetSingleton()
#define g_BuildingPlacer CBuildingPlacer::GetSingleton()
#endif // INCLUDED_INTERACT

View File

@ -19,8 +19,6 @@
#include "Player.h"
#include "network/NetMessage.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
#include "ps/scripting/JSCollection.h"
#include "simulation/LOSManager.h"
@ -32,7 +30,7 @@ CPlayer::CPlayer(size_t playerID):
m_UpdateCB(0),
m_Active(false)
{
m_LOSToken = LOS_GetTokenFor(playerID);
// m_LOSToken = LOS_GetTokenFor(playerID);
// Initialize diplomacy: we need to be neutral to Gaia and enemy to everyone else;
// however, if we are Gaia, we'll just be neutral to everyone; finally, everyone
@ -97,7 +95,6 @@ void CPlayer::ScriptingInit()
// AddClassProperty( L"name", &CPlayer::m_Name );
// AddClassProperty( L"colour", &CPlayer::m_Colour );
AddProperty( L"controlled", &CPlayer::JSI_GetControlledEntities );
CJSObject<CPlayer>::ScriptingInit( "Player" );
}
@ -122,29 +119,11 @@ bool CPlayer::ValidateCommand(CNetMessage* UNUSED(pMsg))
return true;
}
static bool ControllerPredicate( CEntity* entity, void* userdata )
{
return( entity->GetPlayer() == userdata );
}
void CPlayer::GetControlledEntities(std::vector<HEntity>& controlled_entities)
{
g_EntityManager.GetMatchingAsHandles( controlled_entities, ControllerPredicate, this );
}
CStrW CPlayer::JSI_ToString( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return L"[object Player: " + m_Name + L"]";
}
jsval CPlayer::JSI_GetControlledEntities(JSContext* UNUSED(cx))
{
std::vector<HEntity> controlledSet;
GetControlledEntities(controlledSet);
jsval vp = OBJECT_TO_JSVAL( EntityCollection::Create( controlledSet ) );
return( vp );
}
void CPlayer::JSI_SetColour( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* argv )
{
m_Colour=*( ToNative<SPlayerColour>(argv[0]) );

View File

@ -111,11 +111,8 @@ public:
inline void SetActive(bool active)
{ m_Active = active; }
void GetControlledEntities(std::vector<HEntity>& controlled_entities);
// JS Interface Functions
CStrW JSI_ToString( JSContext* context, uintN argc, jsval* argv );
jsval JSI_GetControlledEntities( JSContext* context );
void JSI_SetColour(JSContext *context, uintN argc, jsval *argv);
jsval_t JSI_GetColour(JSContext *context, uintN argc, jsval *argv);
void JSI_SetDiplomaticStance(JSContext *context, uintN argc, jsval *argv);

View File

@ -40,13 +40,6 @@
#include "ps/LoaderThunks.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/EntityManager.h"
#include "simulation/EntityManager.h"
#include "simulation/LOSManager.h"
#include "simulation/TerritoryManager.h"
#include "simulation/TriggerManager.h"
#include "simulation/Projectile.h"
#include "simulation2/Simulation2.h"
#define LOG_CATEGORY L"world"
@ -68,10 +61,8 @@ CWorld::CWorld(CGame *pGame):
m_pGame(pGame),
m_Terrain(new CTerrain()),
m_UnitManager(new CUnitManager()),
m_EntityManager(new CEntityManager()),
m_ProjectileManager(new CProjectileManager()),
m_LOSManager(new CLOSManager()),
m_TerritoryManager(new CTerritoryManager())
m_LOSManager(NULL),
m_TerritoryManager(NULL)
{
}
@ -82,9 +73,6 @@ CWorld::CWorld(CGame *pGame):
**/
void CWorld::Initialize(CGameAttributes *pAttribs)
{
// TODO: Find a better way of handling these global things
ONCE(RegMemFun(CEntityTemplateCollection::GetSingletonPtr(), &CEntityTemplateCollection::LoadTemplates, L"LoadTemplates", 15));
// Load the map, if one was specified
if (pAttribs->m_MapFile.length())
{
@ -94,11 +82,9 @@ void CWorld::Initialize(CGameAttributes *pAttribs)
try {
reader = new CMapReader;
CTriggerManager* pTriggerManager = NULL;
if (!g_UseSimulation2)
pTriggerManager = &g_TriggerManager;
reader->LoadMap(mapfilename, m_Terrain, m_UnitManager, g_Renderer.GetWaterManager(),
g_Renderer.GetSkyManager(), &g_LightEnv, m_pGame->GetView()->GetCamera(), m_pGame->GetView()->GetCinema(),
pTriggerManager, m_pGame->GetSimulation2(), m_EntityManager);
pTriggerManager, m_pGame->GetSimulation2(), NULL);
// fails immediately, or registers for delay loading
} catch (PSERROR_File& err) {
delete reader;
@ -127,11 +113,7 @@ void CWorld::RegisterInit(CGameAttributes *pAttribs)
CWorld::~CWorld()
{
delete m_Terrain;
delete m_EntityManager;
delete m_UnitManager; // must come after deleting EntityManager
delete m_ProjectileManager;
delete m_LOSManager;
delete m_TerritoryManager;
}
@ -145,6 +127,6 @@ void CWorld::RewriteMap()
CMapWriter::RewriteAllMaps(m_Terrain, m_UnitManager,
g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(),
&g_LightEnv, m_pGame->GetView()->GetCamera(),
m_pGame->GetView()->GetCinema(), &g_TriggerManager,
m_pGame->GetSimulation2(), m_EntityManager);
m_pGame->GetView()->GetCinema(), NULL,
m_pGame->GetSimulation2(), NULL);
}

View File

@ -63,14 +63,6 @@ class CWorld
* pointer to the CUnitManager that holds all the units in the world.
**/
CUnitManager *m_UnitManager;
/**
* pointer to the CEntityManager that holds all the entities in the world.
**/
CEntityManager *m_EntityManager;
/**
* pointer to the CProjectileManager that holds all the projectiles in the world.
**/
CProjectileManager *m_ProjectileManager;
/**
* pointer to the CLOSManager that holds the visibility matrix for the world.
**/
@ -108,20 +100,6 @@ public:
**/
inline CUnitManager &GetUnitManager()
{ return *m_UnitManager; }
/**
* Get a reference to the entity manager object.
*
* @return CWorld CEntityManager & dereferenced m_EntityManager.
**/
inline CEntityManager &GetEntityManager()
{ return *m_EntityManager; }
/**
* Get a reference to the projectile manager object.
*
* @return CProjectileManager & dereferenced m_ProjectileManager.
**/
inline CProjectileManager &GetProjectileManager()
{ return *m_ProjectileManager; }
/**
* Get the pointer to the LOS manager object.
*

View File

@ -17,5 +17,3 @@
#include "precompiled.h"
#include "JSCollection.h"
#include "ps/Interact.h"

View File

@ -21,7 +21,7 @@
// object.
#include "scripting/ScriptingHost.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptObject.h"
#include "scripting/JSConversions.h"
#ifndef INCLUDED_JSCOLLECTION

View File

@ -1,115 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// JavaScript interface to native code selection and group objects
#include "precompiled.h"
#include "JSInterface_Selection.h"
#include "ps/scripting/JSCollection.h"
#include "ps/Interact.h"
#include "simulation/Entity.h"
JSBool JSI_Selection::getSelection( JSContext* UNUSED(cx), JSObject* UNUSED(obj),
jsval UNUSED(id), jsval* vp )
{
*vp = OBJECT_TO_JSVAL( EntityCollection::CreateReference( &( g_Selection.m_selected ) ) );
return( JS_TRUE );
}
JSBool JSI_Selection::SetSelection( JSContext* cx, JSObject* UNUSED(obj),
jsval UNUSED(id), jsval* vp )
{
if( !JSVAL_IS_OBJECT( *vp ) )
{
JS_ReportError( cx, "Not a valid Collection" );
*vp = JSVAL_NULL;
return( JS_TRUE );
}
JSObject* selectionArray = JSVAL_TO_OBJECT( *vp );
EntityCollection::CJSCollectionData* Info = (EntityCollection::CJSCollectionData*)JS_GetInstancePrivate( cx, selectionArray, &EntityCollection::JSI_class, NULL );
if( !Info )
{
JS_ReportError( cx, "Not a valid Collection" );
*vp = JSVAL_NULL;
return( JS_TRUE );
}
g_Selection.ClearSelection();
std::vector<HEntity>::iterator it;
for( it = Info->m_Data->begin(); it < Info->m_Data->end(); it++ )
g_Selection.AddSelection( *it );
return( JS_TRUE );
}
JSBool JSI_Selection::getGroups( JSContext* cx, JSObject* UNUSED(obj),
jsval UNUSED(id), jsval* vp )
{
JSObject* groupsArray = JS_NewArrayObject( cx, 0, NULL );
JS_AddRoot( cx, &groupsArray );
for( i8 groupId = 0; groupId < MAX_GROUPS; groupId++ )
{
jsval v = OBJECT_TO_JSVAL( EntityCollection::CreateReference( &( g_Selection.m_groups[groupId] ) ) );
JS_SetElement( cx, groupsArray, groupId, &v );
}
*vp = OBJECT_TO_JSVAL( groupsArray );
JS_RemoveRoot( cx, &groupsArray );
return( JS_TRUE );
}
JSBool JSI_Selection::setGroups( JSContext* cx, JSObject* UNUSED(obj),
jsval UNUSED(id), jsval* vp )
{
JSObject* groupsArray;
if( !JSVAL_IS_OBJECT( *vp ) || !JS_IsArrayObject( cx, groupsArray = JSVAL_TO_OBJECT( *vp ) ) )
{
JS_ReportError( cx, "Not a valid group array" );
*vp = JSVAL_NULL;
return( JS_TRUE );
}
for( i8 groupId = 0; groupId < MAX_GROUPS; groupId++ )
{
jsval v;
if( JS_GetElement( cx, groupsArray, groupId, &v ) && JSVAL_IS_OBJECT( v ) )
{
JSObject* group = JSVAL_TO_OBJECT( v );
EntityCollection::CJSCollectionData* Info = (EntityCollection::CJSCollectionData*)JS_GetInstancePrivate( cx, group, &EntityCollection::JSI_class, NULL );
if( Info )
{
g_Selection.m_groups[groupId].clear();
std::vector<HEntity>::iterator it;
for( it = Info->m_Data->begin(); it < Info->m_Data->end(); it++ )
g_Selection.AddToGroup( groupId, *it );
}
}
}
return( JS_TRUE );
}

View File

@ -1,44 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// JSInterface_Selection.h
//
// The JavaScript wrapper around collections of entities
// (notably the selection and groups objects)
#include "scripting/ScriptingHost.h"
#ifndef INCLUDED_JSI_SELECTION
#define INCLUDED_JSI_SELECTION
namespace JSI_Selection
{
void init();
void finalize( JSContext* cx, JSObject* obj );
JSBool getSelection( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool SetSelection( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool getGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool setGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool IsValidContextOrder( JSContext* context, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool getContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool setContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp );
}
#endif

View File

@ -435,7 +435,7 @@ void CPatchRData::Update()
ssize_t vsize=PATCH_SIZE+1;
SColor4ub baseColour = terrain->GetBaseColour();
if (g_Game && !g_UseSimulation2)
if (g_Game && false) // XXX: need to implement this for new sim system
{
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();

View File

@ -40,8 +40,6 @@
#include "ps/Player.h"
#include "ps/Loader.h"
#include "ps/ProfileViewer.h"
#include "simulation/LOSManager.h"
#include "simulation/TerritoryManager.h"
#include "graphics/Camera.h"
#include "graphics/Texture.h"
#include "graphics/LightEnv.h"
@ -1261,7 +1259,7 @@ void CRenderer::RenderSubmissions()
if (g_Game && m_RenderTerritories)
{
g_Game->GetWorld()->GetTerritoryManager()->RenderTerritories();
// g_Game->GetWorld()->GetTerritoryManager()->RenderTerritories(); // TODO: implement in new sim system
ogl_WarnIfError();
}

View File

@ -603,7 +603,7 @@ void TerrainRenderer::RenderWater()
-100.0f, WaterMgr->m_WaterMaxAlpha);
float losMod = 1.0f;
if (!g_UseSimulation2)
if (false) // XXX: need to implement this for new sim system
{
for(size_t k=0; k<4; k++)
{

View File

@ -19,7 +19,7 @@
#include "DOMEvent.h"
#include "lib/timer.h"
#include "ps/Profile.h"
#include "simulation/ScriptObject.h"
#include "ScriptObject.h"
IEventTarget::~IEventTarget()
{

View File

@ -1,105 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// GameEvents.h
// Defines a singleton class, g_JSGameEvents that fires certain events on
// request (Fire*). This serves to notify scripts of important game events.
// The CScriptEvent-derived events are declared here as well,
// with their type set to one of EventTypes.h's EEventType.
#ifndef INCLUDED_GAMEEVENTS
#define INCLUDED_GAMEEVENTS
#include "DOMEvent.h"
#include "EventTypes.h"
#include "ps/Singleton.h"
class CGameEvents : public IEventTarget, public Singleton<CGameEvents>
{
// Game events don't really run on an object
JSObject* GetScriptExecContext( IEventTarget* UNUSED(target) ) { return( g_ScriptingHost.GetGlobalObject() ); }
// Some events
class CEventSelectionChanged : public CScriptEvent
{
bool m_CausedByPlayer;
public:
CEventSelectionChanged(bool CausedByPlayer):
CScriptEvent( L"selectionChanged", EVENT_SELECTION_CHANGED, false ),
m_CausedByPlayer(CausedByPlayer)
{
AddLocalProperty( L"byPlayer", &m_CausedByPlayer, true );
}
};
class CEventWorldClick: public CScriptEvent
{
int m_Button;
int m_Clicks;
int m_Order;
int m_Action;
int m_SecondaryOrder;
int m_SecondaryAction;
CEntity *m_Entity;
int m_X, m_Y;
public:
CEventWorldClick(int button, int clicks, int order, int action,
int secOrder, int secAction, CEntity *ent, int x, int y):
CScriptEvent(L"worldClick", EVENT_WORLD_CLICK, false),
m_Button(button),
m_Clicks(clicks),
m_Order(order),
m_Action(action),
m_SecondaryOrder(secOrder),
m_SecondaryAction(secAction),
m_Entity(ent),
m_X(x),
m_Y(y)
{
AddLocalProperty(L"button", &m_Button);
AddLocalProperty(L"clicks", &m_Clicks);
AddLocalProperty(L"order", &m_Order);
AddLocalProperty(L"action", &m_Action);
AddLocalProperty(L"secondaryOrder", &m_SecondaryOrder);
AddLocalProperty(L"secondaryAction", &m_SecondaryAction);
if (ent)
AddLocalProperty(L"entity", &m_Entity);
else
AddProperty(L"entity", JSVAL_NULL);
AddLocalProperty(L"x", &m_X);
AddLocalProperty(L"y", &m_Y);
}
};
public:
void FireSelectionChanged( bool CausedByPlayer )
{
CEventSelectionChanged evt( CausedByPlayer );
DispatchEvent( &evt );
}
void FireWorldClick(int button, int clicks, int order, int action,
int secOrder, int secAction, CEntity *ent, int x, int y)
{
CEventWorldClick evt(button, clicks, order, action, secOrder, secAction, ent, x, y);
DispatchEvent(&evt);
}
};
#define g_JSGameEvents CGameEvents::GetSingleton()
#endif

View File

@ -18,30 +18,15 @@
#include "precompiled.h"
#include "JSConversions.h"
#include "simulation/Entity.h"
#include "graphics/ObjectManager.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/Parser.h"
#include "ps/Player.h"
#include "simulation/EntityTemplate.h"
#include "lib/sysdep/sysdep.h" // isfinite
#include <math.h>
#include <cfloat>
#include "scripting/ScriptableComplex.inl"
// HEntity
template<> HEntity* ToNative<HEntity>( JSContext* cx, JSObject* obj )
{
CEntity* e = ToNative<CEntity>( cx, obj );
return( e ? &( e->me ) : NULL );
}
template<> JSObject* ToScript<HEntity>( HEntity* Native )
{
return( ToScript<CEntity>( &( **Native ) ) );
}
// CPlayer*
template<> bool ToPrimitive<CPlayer*>( JSContext* cx, jsval v, CPlayer*& Storage )
{
@ -57,22 +42,6 @@ template<> JSObject* ToScript<CPlayer*>( CPlayer** Native )
return( ToScript<CPlayer>( *Native ) );
}
// CEntityTemplate*
template<> bool ToPrimitive<CEntityTemplate*>( JSContext* cx, jsval v, CEntityTemplate*& Storage )
{
if( !JSVAL_IS_OBJECT( v ) || ( v == JSVAL_NULL ) ) return( false );
CEntityTemplate* Data = (CEntityTemplate*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( v ), &CEntityTemplate::JSI_class, NULL );
if( !Data ) return( false );
Storage = Data;
return( true );
}
template<> JSObject* ToScript<CEntityTemplate*>( CEntityTemplate** Native )
{
return( ToScript<CEntityTemplate>( *Native ) );
}
// CVector3D
template<> CVector3D* ToNative<CVector3D>( JSContext* cx, JSObject* obj )

View File

@ -22,9 +22,6 @@
#include "scripting/ScriptingHost.h"
class CEntity;
class HEntity;
class CEntityTemplate;
class CStrW;
class CScriptObject;
class CObjectEntry;
@ -111,18 +108,10 @@ template<> CVector3D* ToNative<CVector3D>( JSContext* cx, JSObject* obj );
template<> JSObject* ToScript<CVector3D>( CVector3D* Native );
template<> jsval ToJSVal<CVector3D>( const CVector3D& Native );
// CEntityTemplate
template<> bool ToPrimitive<CEntityTemplate*>( JSContext* cx, jsval v, CEntityTemplate*& Storage );
template<> JSObject* ToScript<CEntityTemplate*>( CEntityTemplate** Native );
// CObjectEntry
template<> bool ToPrimitive<CObjectEntry>( JSContext* cx, jsval v, CObjectEntry*& Storage );
template<> jsval ToJSVal<CObjectEntry>( CObjectEntry*& Native );
// HEntity
template<> HEntity* ToNative<HEntity>( JSContext* cx, JSObject* obj );
template<> JSObject* ToScript<HEntity>( HEntity* Native );
// CPlayer*
template<> bool ToPrimitive<CPlayer*>( JSContext* cx, jsval v, CPlayer*& Storage );
template<> JSObject* ToScript<CPlayer*>( CPlayer** Native );

View File

@ -17,23 +17,10 @@
#include "precompiled.h"
#include "Scheduler.h"
#include "Entity.h"
int simulationTime;
int frameCount;
/*
void CScheduler::PushTime( int delay, const HEntity& destination, const CMessage* message )
{
timeMessage.push( SDispatchObjectMessage( destination, simulationTime + delay, message ) );
}
void CScheduler::PushFrame( int delay, const HEntity& destination, const CMessage* message )
{
frameMessage.push( SDispatchObjectMessage( destination, frameCount + delay, message ) );
}
*/
CScheduler::CScheduler()
{
m_nextTaskId = 1;

View File

@ -27,7 +27,6 @@
#include <list>
#include <set>
#include "EntityHandles.h"
#include "ps/Singleton.h"
#include "ps/CStr.h"
#include "scripting/ScriptableObject.h"

View File

@ -25,7 +25,7 @@
#include "ScriptGlue.h"
#include "JSConversions.h"
#include "GameEvents.h"
#include "Scheduler.h"
#include "ScriptableComplex.inl"
@ -49,29 +49,16 @@
#include "ps/Globals.h" // g_frequencyFilter
#include "ps/GameSetup/GameSetup.h"
#include "ps/Hotkey.h"
#include "ps/Interact.h"
#include "ps/ProfileViewer.h"
#include "ps/World.h"
#include "ps/i18n.h"
#include "ps/scripting/JSCollection.h"
#include "ps/scripting/JSInterface_Console.h"
#include "ps/scripting/JSInterface_Selection.h"
#include "ps/scripting/JSInterface_VFS.h"
#include "renderer/Renderer.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation/Entity.h"
#include "simulation/EntityFormation.h"
#include "simulation/EntityHandles.h"
#include "simulation/EntityManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/FormationManager.h"
#include "simulation/LOSManager.h"
#include "simulation/Scheduler.h"
#include "simulation/Simulation.h"
#include "simulation/TechnologyCollection.h"
#include "simulation/TriggerManager.h"
#define LOG_CATEGORY L"script"
extern bool g_TerrainModified;
@ -122,209 +109,6 @@ JSBool WriteLog(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
}
//-----------------------------------------------------------------------------
// Entity
//-----------------------------------------------------------------------------
// Retrieve the entity currently occupying the specified handle.
// params: handle [int]
// returns: entity
JSBool GetEntityByUnitID( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(1);
*rval = JSVAL_NULL;
int uid;
try
{
uid = ToPrimitive<int>( argv[0] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid parameter" );
return( JS_TRUE );
}
CUnit* unit = g_Game->GetWorld()->GetUnitManager().FindByID( uid );
if( !unit || !unit->GetEntity() )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
*rval = OBJECT_TO_JSVAL( unit->GetEntity()->GetScript() );
return( JS_TRUE );
}
// Look up an EntityTemplate by name.
// params: template name [wstring]
// returns: entity template object
JSBool GetEntityTemplate( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAM_RANGE(1, 2);
*rval = JSVAL_NULL;
CStrW templateName;
CPlayer* player = 0;
try
{
templateName = g_ScriptingHost.ValueToUCString( argv[0] );
if( argc == 2 )
{
player = ToNative<CPlayer>( argv[1] );
}
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid template identifier" );
return( JS_TRUE );
}
CEntityTemplate* v = g_EntityTemplateCollection.GetTemplate( templateName, player );
if( !v )
{
JS_ReportError( cx, "No such template: %s", CStr(templateName).c_str() );
return( JS_TRUE );
}
*rval = OBJECT_TO_JSVAL( v->GetScript() );
return( JS_TRUE );
}
JSBool GetPlayerUnitCount( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(2);
const size_t playerNum = ToPrimitive<size_t>( argv[0] );
const CStrW unitName = ToPrimitive<CStrW>( argv[1] );
const int unitCount = g_EntityManager.GetPlayerUnitCount(playerNum, unitName);
*rval = ToJSVal( unitCount );
return JS_TRUE;
}
// Get the state of a given hotkey (from the hotkeys file)
JSBool isOrderQueued( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_NO_PARAMS();
*rval = ToJSVal(hotkeys[HOTKEY_ORDER_QUEUE]);
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// formations
//-----------------------------------------------------------------------------
JSBool CreateEntityFormation( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(2);
CEntityList entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
CStrW name = ToPrimitive<CStrW>( argv[1] );
g_FormationManager.CreateFormation( entities, name );
*rval = JSVAL_VOID;
return JS_TRUE;
}
JSBool RemoveFromFormation( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(1);
CEntityList entities;
if (JS_InstanceOf(cx, JSVAL_TO_OBJECT(argv[0]), &CEntity::JSI_class, NULL))
entities.push_back( (ToNative<CEntity>(argv[0])) ->me);
else
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
*rval = g_FormationManager.RemoveUnitList(entities) ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
JSBool LockEntityFormation( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(1);
CEntity* entity = ToNative<CEntity>( argv[0] );
entity->GetFormation()->SetLock( ToPrimitive<bool>( argv[1] ) );
*rval = JSVAL_VOID;
return JS_TRUE;
}
JSBool IsFormationLocked( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(1);
CEntity* entity = ToNative<CEntity>( argv[0] );
*rval = entity->GetFormation()->IsLocked() ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Techs
//-----------------------------------------------------------------------------
JSBool GetTechnology( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(2);
CStrW name;
CPlayer* player;
try
{
name = g_ScriptingHost.ValueToUCString( argv[0] );
player = ToNative<CPlayer>( argv[1] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid parameters for GetTechnology (expected name and player)" );
return( JS_TRUE );
}
*rval = JSVAL_NULL;
CTechnology* tech = g_TechnologyCollection.GetTechnology( name, player );
if ( tech )
*rval = ToJSVal( tech );
else
g_Console->InsertMessage( L"Warning: Invalid tech template name \"%ls\" passed for GetTechnology()", name.c_str() );
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Events
//-----------------------------------------------------------------------------
// Register a global handler for the specified DOM event.
// params: event type name [wstring], handler [fragment or function]
// returns: whether it was actually newly registered [bool]
JSBool AddGlobalHandler( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(2);
*rval = BOOLEAN_TO_JSVAL( g_JSGameEvents.AddHandlerJS( cx, argc, argv ) );
return( JS_TRUE );
}
// Remove a previously registered global handler for the specified DOM event.
// params: event type name [wstring], handler [fragment or function]
// returns: whether it was successfully removed [bool]
JSBool RemoveGlobalHandler( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS(2);
*rval = BOOLEAN_TO_JSVAL( g_JSGameEvents.RemoveHandlerJS( cx, argc, argv ) );
return( JS_TRUE );
}
//-----------------------------------------------------------------------------
// Timer
//-----------------------------------------------------------------------------
@ -500,25 +284,6 @@ JSBool SetSimRate(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval
return JS_TRUE;
}
//Generate a random float in [0, 1) using the simulation's random generator
JSBool SimRand(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
{
JSU_REQUIRE_NO_PARAMS();
*rval = ToJSVal( g_Game->GetSimulation()->RandFloat() );
return JS_TRUE;
}
//Generate a random float int between 0 and the given number - 1 using the simulation's RNG
JSBool SimRandInt(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
{
JSU_REQUIRE_PARAMS(1);
JSU_ASSERT(JSVAL_IS_INT(argv[0]), "SimRandInt(): first parameter must be an int");
*rval = ToJSVal( g_Game->GetSimulation()->RandInt(ToPrimitive<int>(argv[0])) );
return JS_TRUE;
}
// Script profiling functions: Begin timing a piece of code with StartJsTimer(num)
// and stop timing with StopJsTimer(num). The results will be printed to stdout
// when the game exits.
@ -975,30 +740,6 @@ JSBool SaveProfileData( JSContext* cx, JSObject* UNUSED(globalObject), uintN arg
return( JS_TRUE );
}
// Activates the building placement cursor for placing a building. The currently selected units
// are then ordered to construct the building if it is placed.
// params: templateName - the name of the entity to place.
// returns: true if cursor was activated, false if cursor was already active.
JSBool StartPlacing( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
CStrW name;
if(argc == 0) {
name = L"hele_ho"; // save some typing during testing
}
else {
if(!ToPrimitive<CStrW>( g_ScriptingHost.GetContext(), argv[0], name ))
{
JS_ReportError( cx, "Invalid template name argument" );
*rval = JSVAL_NULL;
return( JS_FALSE );
}
}
*rval = g_BuildingPlacer.Activate(name) ? JS_TRUE : JS_FALSE;
return( JS_TRUE );
}
// Toggles drawing the sky
JSBool ToggleSky( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
@ -1197,47 +938,6 @@ JSBool SetPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsv
return JS_TRUE;
}
// Get game time
JSBool GetGameTime( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_NO_PARAMS();
if( !g_Game )
{
JS_ReportError( cx, "Game is not started" );
return JS_FALSE;
}
*rval = ToJSVal(g_Game->GetSimulation()->GetTime());
return JS_TRUE;
}
JSBool RegisterTrigger( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS_CPP(1);
CTrigger* trigger = ToNative<CTrigger>( argv[0] );
debug_assert( trigger );
g_TriggerManager.AddTrigger( trigger );
*rval = JSVAL_NULL;
return JS_TRUE;
}
JSBool GetTrigger( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS_CPP(1);
CStrW name = ToPrimitive<CStrW>( argv[0] );
if ( g_TriggerManager.m_TriggerMap.find(name) != g_TriggerManager.m_TriggerMap.end() )
*rval = ToJSVal( g_TriggerManager.m_TriggerMap[name] );
else
{
debug_printf(L"Invalid trigger name %ls", name.c_str());
*rval = JSVAL_NULL;
}
return JS_TRUE;
}
// Reveal map
JSBool RevealMap( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
{
@ -1299,24 +999,6 @@ JSFunctionSpec ScriptFunctionTable[] =
// Console
JS_FUNC("writeConsole", JSI_Console::writeConsole, 1) // external
// Entity
JS_FUNC("getEntityByUnitID", GetEntityByUnitID, 1)
JS_FUNC("GetPlayerUnitCount", GetPlayerUnitCount, 1)
JS_FUNC("getEntityTemplate", GetEntityTemplate, 1)
JS_FUNC("startPlacing", StartPlacing, 1)
// Formation
JS_FUNC("createEntityFormation", CreateEntityFormation, 2)
JS_FUNC("removeFromFormation", RemoveFromFormation, 1)
JS_FUNC("lockEntityFormation", LockEntityFormation, 1)
JS_FUNC("isFormationLocked", IsFormationLocked, 1)
// Trigger
JS_FUNC("registerTrigger", RegisterTrigger, 1)
// Tech
JS_FUNC("getTechnology", GetTechnology, 2)
// Camera
JS_FUNC("setCameraTarget", SetCameraTarget, 1)
@ -1334,13 +1016,6 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("setWaterFullDepth", SetWaterFullDepth, 0)
JS_FUNC("setWaterAlphaOffset", SetWaterAlphaOffset, 0)
// Territory rendering
JS_FUNC("toggleTerritoryRendering", ToggleTerritoryRendering, 0)
// Events
JS_FUNC("addGlobalHandler", AddGlobalHandler, 2)
JS_FUNC("removeGlobalHandler", RemoveGlobalHandler, 2)
// Timer
JS_FUNC("setTimeout", SetTimeout, 2)
JS_FUNC("setInterval", SetInterval, 2)
@ -1348,10 +1023,6 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("cancelTimer", CancelTimer, 0)
JS_FUNC("setSimRate", SetSimRate, 1)
// Random number generator
JS_FUNC("simRand", SimRand, 0)
JS_FUNC("simRandInt", SimRandInt, 1)
// Profiling
JS_FUNC("startXTimer", StartJsTimer, 1)
JS_FUNC("stopXTimer", StopJsTimer, 1)
@ -1387,14 +1058,12 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("exit", ExitProgram, 0)
JS_FUNC("isPaused", IsPaused, 0)
JS_FUNC("setPaused", SetPaused, 1)
JS_FUNC("getGameTime", GetGameTime, 0)
JS_FUNC("vmem", WriteVideoMemToConsole, 0)
JS_FUNC("_rewriteMaps", _RewriteMaps, 0)
JS_FUNC("_lodBias", _LodBias, 0)
JS_FUNC("setCursor", SetCursor, 1)
JS_FUNC("getCursorName", GetCursorName, 0)
JS_FUNC("getFPS", GetFps, 0)
JS_FUNC("isOrderQueued", isOrderQueued, 1)
JS_FUNC("isGameRunning", isGameRunning, 0)
// Miscellany
@ -1413,16 +1082,6 @@ JSFunctionSpec ScriptFunctionTable[] =
// property accessors
//-----------------------------------------------------------------------------
JSBool GetEntitySet( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(argv), jsval* vp )
{
std::vector<HEntity> extant;
g_EntityManager.GetExtantAsHandles(extant);
*vp = OBJECT_TO_JSVAL(EntityCollection::Create(extant));
return JS_TRUE;
}
JSBool GetPlayerSet( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
{
std::vector<CPlayer*>* players = g_Game->GetPlayers();
@ -1493,12 +1152,9 @@ enum ScriptGlobalTinyIDs
JSPropertySpec ScriptGlobalTable[] =
{
{ "selection" , GLOBAL_SELECTION, JSPROP_PERMANENT, JSI_Selection::getSelection, JSI_Selection::SetSelection },
{ "groups" , GLOBAL_GROUPSARRAY, JSPROP_PERMANENT, JSI_Selection::getGroups, JSI_Selection::setGroups },
{ "camera" , GLOBAL_CAMERA, JSPROP_PERMANENT, JSI_Camera::getCamera, JSI_Camera::setCamera },
{ "console" , GLOBAL_CONSOLE, JSPROP_PERMANENT|JSPROP_READONLY, JSI_Console::getConsole, 0 },
{ "lightenv" , GLOBAL_LIGHTENV, JSPROP_PERMANENT, JSI_LightEnv::getLightEnv, JSI_LightEnv::setLightEnv },
{ "entities" , 0, JSPROP_PERMANENT|JSPROP_READONLY, GetEntitySet, 0 },
{ "players" , 0, JSPROP_PERMANENT|JSPROP_READONLY, GetPlayerSet, 0 },
{ "localPlayer", 0, JSPROP_PERMANENT, GetLocalPlayer, SetLocalPlayer },
{ "gaiaPlayer" , 0, JSPROP_PERMANENT|JSPROP_READONLY, GetGaiaPlayer, 0 },

View File

@ -18,7 +18,9 @@
#include "precompiled.h"
#include "ScriptObject.h"
#include "Entity.h"
#include "ScriptingHost.h"
#include "JSConversions.h"
#include "DOMEvent.h"
CScriptObject::CScriptObject()
{

View File

@ -35,7 +35,7 @@ which #includes ScriptableComplex.h.
#define INCLUDED_SCRIPTABLECOMPLEX
#include "scripting/ScriptingHost.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptObject.h"
#include "JSConversions.h"
#include "lib/sysdep/stl.h"

View File

@ -1,626 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "AStarEngine.h"
/* For AStarGoalLowLevel IsPassable/cost */
#include "Collision.h"
#include "Entity.h"
#include "ps/Overlay.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "graphics/TextureEntry.h"
#include "graphics/TerrainProperties.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "ps/Profile.h"
#include "lib/res/graphics/ogl_tex.h"
#include "ps/GameSetup/Config.h"
#define DEFAULT_SEARCH_LIMIT 1000
#define DEFAULT_INIT_NODES 1000
// TODO: do this for real
#define MAXSLOPE 3500
// Node status flags
enum
{
kClear = 0x00, // empty, unexamined
kPassable = 0x01, // examined, not blocked
kBlocked = 0x02, // examined, blocked
kOpen = 0x04, // on the open list
kClosed = 0x08 // on the closed list
};
class PathFindingTerrainOverlay : public TerrainOverlay
{
public:
char random[1021];
std::vector<CVector2D> aPath;
void setPath(const std::vector<CVector2D>& _aPath)
{
aPath =_aPath;
for(size_t k = 0 ; k< aPath.size();k++)
{
aPath[k] = WorldspaceToTilespace( aPath[k] );
}
}
CVector2D WorldspaceToTilespace( const CVector2D &ws )
{
return CVector2D(floor(ws.x/CELL_SIZE), floor(ws.y/CELL_SIZE));
}
bool inPath(ssize_t i, ssize_t j)
{
for(size_t k = 0 ; k<aPath.size();k++)
{
if(aPath[k].x== i && aPath[k].y== j)
return true;
}
return false;
}
virtual void ProcessTile(ssize_t i, ssize_t j)
{
if ( inPath( i, j))
{
RenderTile(CColor(random[(i*79+j*13) % ARRAY_SIZE(random)]/4.f, 1, 0, 0.3f), false);
RenderTileOutline(CColor(1, 1, 1, 1), 1, true);
}
}
};
CAStarEngine::CAStarEngine()
{
mSearchLimit = DEFAULT_SEARCH_LIMIT;
for(int i=0; i<DEFAULT_INIT_NODES; i++)
{
freeNodes.push_back(new AStarNode);
}
mFlagArraySize = 300;
mFlags = new AStarNodeFlag[mFlagArraySize*mFlagArraySize];
memset(mFlags, 0, mFlagArraySize*mFlagArraySize*sizeof(AStarNodeFlag));
// TODO: only instantiate this object when it's going to be used
pathfindingOverlay = new PathFindingTerrainOverlay();
}
CAStarEngine::~CAStarEngine()
{
delete[] mFlags;
std::vector<AStarNode*>::iterator it;
for( it = usedNodes.begin(); it != usedNodes.end(); it++)
{
delete (*it);
}
for( it = freeNodes.begin(); it != freeNodes.end(); it++)
{
delete (*it);
}
delete pathfindingOverlay;
}
/*
void CAStarEngine::TAStarTest()
{
//Kai: added for TA*
std::vector<CEntity*> results;
g_EntityManager.GetExtant(results);
for(int i =0 ; i < results.size(); i++)
{
CEntity* tempHandle = results[i];
debug_printf(L"Entity position: %f %f %f\n", tempHandle->m_position.X,tempHandle->m_position.Y,tempHandle->m_position.Z);
CBoundingObject* m_bounds = tempHandle->m_bounds;
switch( m_bounds->m_type )
{
case CBoundingObject::BOUND_CIRCLE:
{
break;
}
case CBoundingObject::BOUND_OABB:
{
glColor3f( 1, 1, 1 ); // Colour outline with player colour
glBegin(GL_LINES);
glVertex3f( 2, tempHandle->GetAnchorLevel( 2, 2 ) + 0.25f, 2 ); // lower left vertex
glVertex3f( 5, tempHandle->GetAnchorLevel( 5, 5 ) + 0.25f, 5 ); // upper vertex
glEnd();
break;
}
}
if(tempHandler->m_bound_type == CBoundingOjbect::BOUND_OABB)
{
debug_printf(L"Entity bound box: %f\n", tempHandler->m_bound_box.m_v);
}
}
}*/
bool CAStarEngine::FindPath(
const CVector2D &src, const CVector2D &dest, HEntity entity, float radius )
{
mSolved = false;
int iterations = 0;
mGoal->SetDestination(dest);
mGoal->SetRadius(radius);
AStarNode *start = GetFreeASNode();
start->coord = mGoal->GetTile(src);
start->parent = NULL;
start->g = 0;
start->f = start->h = mGoal->DistanceToGoal(start->coord);
ClearOpen();
ClearClosed();
PROFILE_START("memset cache");
memset(mFlags, 0, mFlagArraySize*mFlagArraySize*sizeof(AStarNodeFlag));
PROFILE_END("memset cache");
AddToOpen(start);
AStarNode *best = NULL;
while( iterations<mSearchLimit && (best = RemoveBestOpenNode()) != NULL )
{
iterations++;
PROFILE_START("AddToClosed");
AddToClosed(best);
PROFILE_END("AddToClosed");
if ( mGoal->IsAtGoal(best->coord) )
{
/* Path solved */
mSolved = true;
break;
}
/* Get neighbors of the best node */
std::vector<CVector2D> neighbors;
PROFILE_START("get neighbors");
neighbors = mGoal->GetNeighbors(best->coord, entity);
PROFILE_END("get neighbors");
/* Update the neighbors of the best node */
std::vector<CVector2D>::iterator it;
for( it = neighbors.begin(); it != neighbors.end(); it++ )
{
AStarNode* N = GetFreeASNode();
PROFILE_START("initialize neighbor");
N->coord = *it;
// Assign f,g,h to neighbor
N->g = best->g + mGoal->GetTileCost(best->coord, N->coord);
N->h = mGoal->DistanceToGoal(*it);
N->f = N->g +N->h;
N->parent = best;
PROFILE_END("initialize neighbor");
AStarNode* C;
PROFILE_START("search closed");
C = GetFromClosed(N->coord);
PROFILE_END("search closed");
bool update = false;
if( C!=NULL && (N->f < C->f) )
{
PROFILE_START("remove from closed");
// N is on Closed and N->f is better
RemoveFromClosed(C);
update = true;
PROFILE_END("remove from closed");
}
if (C==NULL || update)
{
PROFILE_START("add to open");
// N is not on Closed
AddToOpen(N);
PROFILE_END("add to open");
}
}
}
if (mSolved && best!=NULL)
{
//debug_printf(L"Number of nodes searched: %d\n", iterations);
ConstructPath(best);
}
//switch on/off grid path drawing by command line arg "-showOverlay"
//it's guarded here to stop setting the drawing path in pathfindingOverlay.
//(efficiency issue)
//the drawing is disabled in the render() function in TerrainOverlay.cpp
if(g_ShowPathfindingOverlay)
{
pathfindingOverlay->setPath(mPath);
}
Cleanup();
return mSolved;
}
void CAStarEngine::ConstructPath( AStarNode* end )
{
std::deque<CVector2D> path;
mPath.clear();
while( end!=NULL && (end->parent)!=NULL )
{
path.push_front(mGoal->GetCoord(end->coord));
end = end->parent;
}
mPath.insert(mPath.begin(), path.begin(), path.end());
}
std::vector<CVector2D> CAStarEngine::GetLastPath()
{
return mPath;
}
void CAStarEngine::SetSearchLimit( int limit )
{
mSearchLimit = limit;
}
void CAStarEngine::AddToOpen( AStarNode* node )
{
/* If not in open, should add, otherwise should promote */
AStarNodeFlag *flag = GetFlag(node->coord);
if (!IsOpen(flag))
{
mOpen.push(node);
}
else
{
mOpen.promote(node);
}
SetOpenFlag(flag);
}
AStarNode* CAStarEngine::RemoveBestOpenNode()
{
if (mOpen.empty())
return NULL;
AStarNode* top;
PROFILE_START("remove from open");
top = mOpen.top();
mOpen.pop();
ClearOpenFlag(GetFlag(top->coord));
PROFILE_END("remove from open");
return top;
}
void CAStarEngine::AddToClosed( AStarNode* node )
{
mClosed[node->coord] = node;
SetClosedFlag(GetFlag(node->coord));
}
void CAStarEngine::RemoveFromClosed( AStarNode* node )
{
mClosed.erase(node->coord);
ClearClosedFlag(GetFlag(node->coord));
}
AStarNode* CAStarEngine::GetFromClosed( const CVector2D& loc )
{
if (!IsClosed(GetFlag(loc)))
{
return NULL;
}
ASNodeHashMap::iterator it = mClosed.find(loc);
return ( it != mClosed.end() ) ? (it->second) : (NULL);
}
void CAStarEngine::ClearOpen()
{
mOpen.clear();
}
void CAStarEngine::ClearClosed()
{
mClosed.clear();
}
AStarNode* CAStarEngine::GetFreeASNode()
{
AStarNode* ret;
PROFILE_START("allocator");
if (!freeNodes.empty())
{
ret = freeNodes.back();
freeNodes.pop_back();
}
else
{
ret = new AStarNode;
}
usedNodes.push_back(ret);
PROFILE_END("allocator");
return ret;
}
void CAStarEngine::Cleanup()
{
std::vector<AStarNode*>::iterator it;
for( it = usedNodes.begin(); it != usedNodes.end(); it++)
{
freeNodes.push_back(*it);
}
usedNodes.clear();
}
void PriQueue::promote( AStarNode *node )
{
if (node == NULL)
{
return;
}
std::vector<AStarNode*>::iterator ind, first;
for( ind = c.begin(); ind!=c.end() && !((*ind)->equals(*node)); ind++ ) { }
if (ind == c.end())
{
push(node);
return;
}
if( (*ind)->f <= node->f ) return;
first = c.begin();
int index = ind-first;
int parent = (index - 1)/2;
while ( index>0 && (*(first+parent))->f > node->f )
{
*(first+index) = *(first+parent);
index = parent;
parent = (parent - 1)/2;
}
*(first+index) = node;
}
void PriQueue::clear()
{
c.clear();
}
CVector2D TilespaceToWorldspace( const CVector2D &ts )
{
return CVector2D(ts.x*CELL_SIZE+CELL_SIZE/2, ts.y*CELL_SIZE+CELL_SIZE/2);
}
CVector2D WorldspaceToTilespace( const CVector2D &ws )
{
return CVector2D(floor(ws.x/CELL_SIZE), floor(ws.y/CELL_SIZE));
}
void AStarGoalLowLevel::SetDestination( const CVector2D &dest )
{
coord = WorldspaceToTilespace(dest);
}
void AStarGoalLowLevel::SetRadius( float r )
{
radius = r;
}
float AStarGoalLowLevel::GetRadius()
{
return radius;
}
float AStarGoalLowLevel::DistanceToGoal( const CVector2D &loc )
{
return ((coord-loc).Length());
}
bool AStarGoalLowLevel::IsAtGoal( const CVector2D &loc )
{
float dx = coord.x - loc.x;
float dy = coord.y - loc.y;
return dx*dx + dy*dy <= radius*radius / (CELL_SIZE*CELL_SIZE); // Scale down radius to tilespace
}
float AStarGoalLowLevel::GetTileCost( const CVector2D& loc1, const CVector2D& loc2 )
{
return (loc2-loc1).Length() - radius;
}
bool AStarGoalLowLevel::IsPassable( const CVector2D &loc, HEntity entity )
{
CTerrain* pTerrain = g_Game->GetWorld()->GetTerrain();
int size = pTerrain->GetTilesPerSide();
if( loc.x<0 || loc.y<0 || loc.x>=size || loc.y>=size )
{
return false;
}
if ( pTerrain->IsPassable(loc, entity) )
{
// If no entity blocking, return true
CVector2D wloc = TilespaceToWorldspace(loc);
CBoundingBox bounds(wloc.x, wloc.y, 0, CELL_SIZE, CELL_SIZE, 3);
if ( GetCollisionObject(&bounds, entity->GetPlayer()) == NULL )
{
return true;
}
}
return false;
}
CVector2D AStarGoalLowLevel::GetCoord( const CVector2D &loc )
{
return TilespaceToWorldspace(loc);
}
CVector2D AStarGoalLowLevel::GetTile( const CVector2D &loc )
{
return WorldspaceToTilespace(loc);
}
std::vector<CVector2D> AStarGoalLowLevel::GetNeighbors( const CVector2D &loc, HEntity entity)
{
std::vector<CVector2D> vec;
for( int xdiff = -1; xdiff <= 1; xdiff++ )
{
for( int ydiff = -1; ydiff <= 1; ydiff++ )
{
if ( xdiff!=0 || ydiff!=0 )
{
CVector2D c = loc;
c.x += xdiff; c.y += ydiff;
if ( IsPassable(c, entity) )
{
vec.push_back(c);
}
}
}
}
return vec;
}
inline AStarNodeFlag* CAStarEngine::GetFlag(const CVector2D &loc)
{
debug_assert(loc.x>=0 && loc.y>=0 && loc.x<mFlagArraySize && loc.y<mFlagArraySize);
return mFlags + (mFlagArraySize * (long)loc.x + (long)loc.y);
}
inline bool CAStarEngine::IsClear(AStarNodeFlag* flag)
{
return (*flag)==kClear;
}
inline bool CAStarEngine::IsClosed(AStarNodeFlag* flag)
{
return ((*flag) & kClosed) != kClear;
}
inline bool CAStarEngine::IsOpen(AStarNodeFlag* flag)
{
return ((*flag) & kOpen) != kClear;
}
inline void CAStarEngine::SetClosedFlag(AStarNodeFlag* flag)
{
*flag |= kClosed;
}
inline void CAStarEngine::SetOpenFlag(AStarNodeFlag* flag)
{
*flag |= kOpen;
}
inline void CAStarEngine::ClearClosedFlag(AStarNodeFlag* flag)
{
*flag &= -kClosed;
}
inline void CAStarEngine::ClearOpenFlag(AStarNodeFlag* flag)
{
*flag &= -kOpen;
}
inline bool CAStarEngine::IsPassable(AStarNodeFlag* flag)
{
return ((*flag) & kPassable) != kClear;
}
inline bool CAStarEngine::IsBlocked(AStarNodeFlag* flag)
{
return ((*flag) & kBlocked) != kClear;
}
inline void CAStarEngine::SetPassableFlag(AStarNodeFlag* flag)
{
*flag |= kPassable;
}
inline void CAStarEngine::SetBlockedFlag(AStarNodeFlag* flag)
{
*flag |= kBlocked;
}

View File

@ -1,212 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ASTARENGINE
#define INCLUDED_ASTARENGINE
#include "ps/Vector2D.h"
#include "ps/Player.h"
#include <queue>
#include "renderer/TerrainOverlay.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "EntityManager.h"
#ifdef USE_DCDT
# include "dcdt/se/se_dcdt.h"
#endif // USE_DCDT
class AStarNode
{
public:
float f, g, h;
AStarNode* parent;
CVector2D coord;
bool operator <(const AStarNode& rhs) const { return f<rhs.f; }
bool equals(const AStarNode& rhs) const
{
return ( coord.x==rhs.coord.x ) && ( coord.y==rhs.coord.y );
}
};
class AStarGoalBase;
class AStarGoalLowLevel;
struct AStarNodeComp
{
bool operator()(const AStarNode* n1, const AStarNode* n2) const
{
return (*n2) < (*n1);
}
};
class CVector2D_hash_compare
{
public:
static const size_t bucket_size = 4;
static const size_t min_buckets = 16;
size_t operator() (const CVector2D& Key) const
{
return (size_t)(Key.x + Key.y*1024.f);
}
bool operator() (const CVector2D& _Key1, const CVector2D& _Key2) const
{
return (_Key1.x < _Key2.x) || (_Key1.x==_Key2.x && _Key1.y < _Key2.y);
}
};
typedef STL_HASH_MAP<CVector2D, AStarNode*, CVector2D_hash_compare> ASNodeHashMap;
class PriQueue
: public std::priority_queue<AStarNode*, std::vector<AStarNode*>, AStarNodeComp>
{
public:
// Promote a node in the PQ, or if it doesn't exist, add it
void promote(AStarNode* node);
void clear();
};
typedef unsigned char AStarNodeFlag;
class PathFindingTerrainOverlay;
class CAStarEngine
{
public:
CAStarEngine();
virtual ~CAStarEngine();
void SetGoal(AStarGoalBase* goal) { mGoal = goal; }
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, float radius=0.0f );
std::vector<CVector2D> GetLastPath();
// The maximum number of nodes that will be expanded before failure is declared
void SetSearchLimit( int limit );
//Kai:added tile overlay for pathfinding
PathFindingTerrainOverlay* pathfindingOverlay;
#ifdef USE_DCDT
SrPolygon pol;
//void TAStarTest();
#endif // USE_DCDT
protected:
AStarGoalBase* mGoal;
private:
int mSearchLimit;
bool mSolved;
std::vector<CVector2D> mPath;
AStarNodeFlag *mFlags;
long mFlagArraySize;
ASNodeHashMap mClosed;
PriQueue mOpen;
std::vector<AStarNode*> freeNodes;
std::vector<AStarNode*> usedNodes;
// AddToOpen will promote if the node already is in Open
void AddToOpen( AStarNode* );
AStarNode* RemoveBestOpenNode();
void AddToClosed( AStarNode* );
void RemoveFromClosed( AStarNode* );
AStarNode* GetFromClosed( const CVector2D& );
void ClearOpen();
void ClearClosed();
void ConstructPath( AStarNode* );
AStarNode* GetFreeASNode();
void Cleanup();
inline AStarNodeFlag* GetFlag(const CVector2D&);
inline bool IsClear(AStarNodeFlag*);
inline bool IsClosed(AStarNodeFlag*);
inline bool IsOpen(AStarNodeFlag*);
inline void SetClosedFlag(AStarNodeFlag*);
inline void ClearClosedFlag(AStarNodeFlag*);
inline void SetOpenFlag(AStarNodeFlag*);
inline void ClearOpenFlag(AStarNodeFlag*);
inline bool IsPassable(AStarNodeFlag*);
inline bool IsBlocked(AStarNodeFlag*);
inline void SetPassableFlag(AStarNodeFlag*);
inline void SetBlockedFlag(AStarNodeFlag*);
};
/**
* An A* goal consists of a destination tile and a radius within which a
* unit must get to the destination. The radius is necessary because for
* actions on a target unit, like attacking or building, the destination
* tile is obstructed by that unit and what we really want is not to get
* to that tile but to get close enough to perform our action.
**/
class AStarGoalBase
{
public:
AStarGoalBase() {}
virtual ~AStarGoalBase() {}
virtual void SetDestination( const CVector2D& ) = 0;
virtual void SetRadius( float r ) = 0;
virtual float DistanceToGoal( const CVector2D& ) = 0;
virtual bool IsAtGoal( const CVector2D& ) = 0;
virtual float GetTileCost( const CVector2D&, const CVector2D& ) = 0;
virtual bool IsPassable( const CVector2D&, HEntity entity) = 0;
virtual std::vector<CVector2D> GetNeighbors( const CVector2D&, HEntity entity) = 0;
virtual CVector2D GetCoord( const CVector2D& ) = 0;
virtual CVector2D GetTile( const CVector2D& ) = 0;
virtual float GetRadius() = 0;
};
class AStarGoalLowLevel : public AStarGoalBase
{
public:
AStarGoalLowLevel(): radius(0.0f) {}
void SetDestination( const CVector2D& dest );
void SetRadius( float r );
float DistanceToGoal( const CVector2D& loc );
bool IsAtGoal( const CVector2D& loc );
float GetTileCost( const CVector2D& loc1, const CVector2D& loc2 );
bool IsPassable( const CVector2D& loc, HEntity entity);
std::vector<CVector2D> GetNeighbors( const CVector2D& loc, HEntity entity);
CVector2D GetCoord( const CVector2D& loc);
CVector2D GetTile( const CVector2D& loc);
float GetRadius();
private:
CVector2D coord;
float radius;
};
class CAStarEngineLowLevel : public CAStarEngine
{
public:
CAStarEngineLowLevel()
{
mGoal = new AStarGoalLowLevel;
}
virtual ~CAStarEngineLowLevel()
{
delete mGoal;
}
};
#endif

View File

@ -1,182 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Aura.h"
#include "EntityManager.h"
#include "Entity.h"
#include "scripting/ScriptableComplex.inl"
#include <algorithm>
CAura::CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, int tickRate, const CVector4D& color, JSObject* handler )
: m_cx(cx), m_source(source), m_name(name), m_radius(radius), m_handler(handler),
m_tickRate(tickRate), m_tickCyclePos(0), m_color(color)
{
JS_AddRoot( m_cx, &m_handler ); // don't GC it so we can call it later
}
CAura::~CAura()
{
JS_RemoveRoot( m_cx, &m_handler );
}
void CAura::Update( int timestep )
{
std::vector<CEntity*> inRange;
CVector3D pos = m_source->m_position;
g_EntityManager.GetInRange( pos.X, pos.Z, m_radius, inRange );
std::vector<CEntity*> prevInfluenced, curInfluenced, entered, exited;
prevInfluenced.reserve(m_influenced.size());
curInfluenced.reserve(m_influenced.size());
for( std::vector<HEntity>::iterator it = m_influenced.begin(); it != m_influenced.end(); it++ )
{
CEntity* ent = *it;
if( ent && ent->m_extant )
{
prevInfluenced.push_back(ent);
}
}
m_influenced.clear();
for( std::vector<CEntity*>::iterator it = inRange.begin(); it != inRange.end(); it++ )
{
CEntity* ent = *it;
if(ent != m_source)
{
curInfluenced.push_back(ent);
m_influenced.push_back( HEntity(ent->me) );
}
}
sort( prevInfluenced.begin(), prevInfluenced.end() );
sort( curInfluenced.begin(), curInfluenced.end() );
jsval rval;
jsval argv[1];
// Call onEnter on any new unit that has entered the aura
jsval enterFunction;
if( JS_GetProperty( m_cx, m_handler, "onEnter", &enterFunction )
&& enterFunction != JSVAL_VOID)
{
std::back_insert_iterator<std::vector<CEntity*> > ins( entered );
set_difference( curInfluenced.begin(), curInfluenced.end(),
prevInfluenced.begin(), prevInfluenced.end(),
ins );
for( std::vector<CEntity*>::iterator it = entered.begin(); it != entered.end(); it++ )
{
argv[0] = OBJECT_TO_JSVAL( (*it)->GetScript() );
JS_CallFunctionValue( m_cx, m_handler, enterFunction, 1, argv, &rval );
(*it)->m_aurasInfluencingMe.insert( this );
}
}
// Call onExit on any unit that has exited the aura
jsval exitFunction;
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
std::back_insert_iterator<std::vector<CEntity*> > ins( exited );
set_difference( prevInfluenced.begin(), prevInfluenced.end(),
curInfluenced.begin(), curInfluenced.end(),
ins );
for( std::vector<CEntity*>::iterator it = exited.begin(); it != exited.end(); it++ )
{
argv[0] = OBJECT_TO_JSVAL( (*it)->GetScript() );
JS_CallFunctionValue( m_cx, m_handler, exitFunction, 1, argv, &rval );
(*it)->m_aurasInfluencingMe.erase( this );
}
}
m_tickCyclePos += timestep;
if( m_tickRate > 0 && m_tickCyclePos > m_tickRate )
{
// It's time to tick; call OnTick on any unit that is in the aura
jsval tickFunction;
if( JS_GetProperty( m_cx, m_handler, "onTick", &tickFunction )
&& tickFunction != JSVAL_VOID )
{
for( std::vector<CEntity*>::iterator it = curInfluenced.begin(); it != curInfluenced.end(); it++ )
{
argv[0] = OBJECT_TO_JSVAL( (*it)->GetScript() );
JS_CallFunctionValue( m_cx, m_handler, tickFunction, 1, argv, &rval );
}
}
// Reset cycle pos
m_tickCyclePos %= m_tickRate;
}
}
void CAura::RemoveAll()
{
jsval rval;
jsval argv[1];
jsval exitFunction;
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
// Call the exit function on everything in our influence
for( std::vector<HEntity>::iterator it = m_influenced.begin(); it != m_influenced.end(); it++ )
{
CEntity* ent = *it;
if( ent && ent->m_extant )
{
argv[0] = OBJECT_TO_JSVAL( ent->GetScript() );
JS_CallFunctionValue( m_cx, m_handler, exitFunction, 1, argv, &rval );
(*it)->m_aurasInfluencingMe.erase( this );
}
}
}
m_influenced.clear();
}
// Remove an entity from the aura, but does not remove the aura from its
// m_aurasInfluencingMe. (Used when the entity is asking to be removed from
// the aura and will clear its own m_aurasInfluencingMe list afterwards).
void CAura::Remove( CEntity* ent )
{
jsval rval;
jsval argv[1];
jsval exitFunction;
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
// Call the exit function on it
argv[0] = OBJECT_TO_JSVAL( ent->GetScript() );
JS_CallFunctionValue( m_cx, m_handler, exitFunction, 1, argv, &rval );
// Remove it from the m_influenced array
for( size_t i=0; i < m_influenced.size(); i++ )
{
if( ((CEntity*) m_influenced[i]) == ent )
{
m_influenced.erase( m_influenced.begin() + i );
break;
}
}
}
}

View File

@ -1,58 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_AURA
#define INCLUDED_AURA
#include "EntityHandles.h"
#include "maths/Vector4D.h"
#include "scripting/SpiderMonkey.h"
#include "ps/CStr.h"
class CEntity;
class CAura
{
public:
JSContext* m_cx;
CEntity* m_source;
CStrW m_name;
CVector4D m_color;
float m_radius; // In graphics units
int m_tickRate; // In milliseconds
JSObject* m_handler;
std::vector<HEntity> m_influenced;
int m_tickCyclePos; // Add time to this until it's time to tick again
CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, int tickRate, const CVector4D& color, JSObject* handler );
~CAura();
// Remove all entities from under our influence; this isn't done in the destructor since
// the destructor needs to be called at the end of the program when some CEntities
// have been deleted despite our keeping handles to them, in addition to just when an
// entity dies. RemoveAll will only be called in the second case.
void RemoveAll();
// Forcefully removes an entity from the aura. Useful so that a unit that is killed can
// notify its auras to remove it before it dies (so they can still access its data).
void Remove( CEntity* ent );
// Called to update the aura each simulation frame.
void Update( int timestep );
};
#endif

View File

@ -1,296 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "BoundingObjects.h"
#include "lib/ogl.h"
#include "maths/MathUtil.h"
bool CBoundingObject::Intersects( CBoundingObject* obj )
{
CVector2D delta = m_pos - obj->m_pos;
if( !delta.within( m_radius + obj->m_radius ) )
return( false );
if( obj->m_type > m_type ) // More complex types get the burden of processing.
{
return( obj->LooselyIntersects( this, delta ) );
}
else
return( LooselyIntersects( obj, delta ) );
}
bool CBoundingObject::Contains( const CVector2D& point )
{
CVector2D delta = m_pos - point;
if( !delta.within( m_radius ) )
return( false );
return( LooselyContains( point, delta ) );
}
void CBoundingObject::SetPosition( float x, float y )
{
m_pos.x = x; m_pos.y = y;
}
void CBoundingObject::SetHeight( float height )
{
m_height = height;
}
CBoundingCircle::CBoundingCircle( float x, float y, float radius, float height )
{
m_type = BOUND_CIRCLE;
SetPosition( x, y );
SetRadius( radius );
SetHeight( height );
}
CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy )
{
m_type = BOUND_CIRCLE;
SetPosition( x, y );
SetRadius( copy->m_radius );
SetHeight( copy->m_height );
}
void CBoundingCircle::SetRadius( float radius )
{
m_radius = radius;
}
bool CBoundingCircle::LooselyIntersects( CBoundingObject* obj, const CVector2D& UNUSED(delta) )
{
debug_assert( obj->m_type == BOUND_CIRCLE );
// Easy enough. The only time this gets called is a circle-circle collision,
// but we know the circles collide (they passed the trivial rejection step)
return( true );
}
bool CBoundingCircle::LooselyContains( const CVector2D& UNUSED(point), const CVector2D& UNUSED(delta) )
{
return( true );
}
void CBoundingCircle::Render( float height )
{
glBegin( GL_LINE_LOOP );
for( int i = 0; i < 10; i++ )
{
float ang = i * 2 * (float)M_PI / 10.0f;
float x = m_pos.x + m_radius * sin( ang );
float y = m_pos.y + m_radius * cos( ang );
glVertex3f( x, height, y );
}
glEnd();
}
CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, float width, float depth, float height )
{
m_type = BOUND_OABB;
SetPosition( x, y );
SetDimensions( width, depth );
SetHeight( height );
SetOrientation( u );
}
CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, CBoundingBox* copy )
{
m_type = BOUND_OABB;
SetPosition( x, y );
SetDimensions( copy->GetWidth(), copy->GetDepth() );
SetHeight( copy->m_height );
SetOrientation( u );
}
CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, float depth, float height )
{
m_type = BOUND_OABB;
SetPosition( x, y );
SetDimensions( width, depth );
SetHeight( height );
SetOrientation( orientation );
}
CBoundingBox::CBoundingBox( float x, float y, float orientation, CBoundingBox* copy )
{
m_type = BOUND_OABB;
SetPosition( x, y );
SetDimensions( copy->GetWidth(), copy->GetDepth() );
SetHeight( copy->m_height );
SetOrientation( orientation );
}
void CBoundingBox::SetDimensions( float width, float depth )
{
m_w = width / 2.0f;
m_d = depth / 2.0f;
m_radius = sqrt( ( m_w * m_w ) + ( m_d * m_d ) );
}
void CBoundingBox::SetOrientation( float orientation )
{
m_u.x = sin( orientation );
m_u.y = cos( orientation );
m_v.x = m_u.y;
m_v.y = -m_u.x;
}
void CBoundingBox::SetOrientation( const CVector2D& u )
{
m_u = u;
m_v.x = m_u.y;
m_v.y = -m_u.x;
}
bool CBoundingBox::LooselyIntersects( CBoundingObject* obj, const CVector2D& delta )
{
if( obj->m_type == BOUND_CIRCLE )
{
// Imperfect but quick...
CBoundingCircle* c = (CBoundingCircle*)obj;
float deltad = fabs( delta.Dot( m_u ) );
if( deltad > ( m_d + c->m_radius ) ) return( false );
float deltaw = fabs( delta.Dot( m_v ) );
if( deltaw > ( m_w + c->m_radius ) ) return( false );
return( true );
}
else
{
// Another OABB:
// Seperable axis theorem. (Optimizations: Algorithmic done, low-level stuff not.)
// Debugging this can often be quite entertaining.
CBoundingBox* b = (CBoundingBox*)obj;
// SAT in a nutshell: If two boxes are disjoint, there's an axis where their projections don't overlap
// That axis (in 2D) will run parallel to a side of one of the boxes
// This code computes projections of boxes onto each axis in turn - hopefully quickly
// then does simple max/min checks to determine overlap
// uv, vu, uu, vv are dot-products of our u- and v- axes of each box.
// prj1, prj2 are two coordinates locating the projections of two corners of a box onto an axis.
// dm is the distance between the boxes, projected onto the axis.
// Lots of nice symmetries used to help speed things up
// Note that a trivial-rejection test has already taken place by this point.
float uv, vu, uu, vv, prj1, prj2, dm;
uv = m_u.Dot( b->m_v );
vu = m_v.Dot( b->m_u );
uu = m_u.Dot( b->m_u );
vv = m_v.Dot( b->m_v );
// Project box 2 onto v-axis of box 1
prj1 = fabs( vu * b->m_d + vv * b->m_w );
prj2 = fabs( vu * b->m_d - vv * b->m_w );
dm = delta.Dot( m_v );
if( prj1 > prj2 )
{
if( ( dm - prj1 ) > m_w ) return( false );
}
else
if( ( dm - prj2 ) > m_w ) return( false );
// Project box 2 onto u-axis of box 1
prj1 = fabs( uu * b->m_d + uv * b->m_w );
prj2 = fabs( uu * b->m_d - uv * b->m_w );
dm = delta.Dot( m_u );
if( prj1 > prj2 )
{
if( ( dm - prj1 ) > m_d ) return( false );
}
else
if( ( dm - prj2 ) > m_d ) return( false );
// Project box 1 onto v-axis of box 2
prj1 = fabs( uv * m_d + vv * m_w );
prj2 = fabs( uv * m_d - vv * m_w );
dm = delta.Dot( b->m_v );
if( prj1 > prj2 )
{
if( ( dm - prj1 ) > b->m_w ) return( false );
}
else
if( ( dm - prj2 ) > b->m_w ) return( false );
// Project box 1 onto u-axis of box 2
prj1 = fabs( uu * m_d + vu * m_w );
prj2 = fabs( uu * m_d - vu * m_w );
dm = delta.Dot( b->m_u );
if( prj1 > prj2 )
{
if( ( dm - prj1 ) > b->m_d ) return( false );
}
else
if( ( dm - prj2 ) > b->m_d ) return( false );
return( true );
}
}
bool CBoundingBox::LooselyContains( const CVector2D& UNUSED(point), const CVector2D& delta )
{
float deltad = fabs( delta.Dot( m_u ) );
if( deltad > m_d ) return( false );
float deltaw = fabs( delta.Dot( m_v ) );
if( deltaw > m_w ) return( false );
return( true );
}
void CBoundingBox::Render( float height )
{
glBegin( GL_LINE_LOOP );
CVector2D p;
p = m_pos + m_u * m_d + m_v * m_w;
glVertex3f( p.x, height, p.y );
p = m_pos + m_u * m_d - m_v * m_w;
glVertex3f( p.x, height, p.y );
p = m_pos - m_u * m_d - m_v * m_w;
glVertex3f( p.x, height, p.y );
p = m_pos - m_u * m_d + m_v * m_w;
glVertex3f( p.x, height, p.y );
glEnd();
}

View File

@ -1,91 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// BoundingObjects.h
//
// Bounding circle and object-aligned bounding box. 2D, for simulation code.
//
// Note: object-aligned bounding boxes are often referred to as oriented bounding boxes (OBBs)
#ifndef INCLUDED_BOUNDINGOBJECTS
#define INCLUDED_BOUNDINGOBJECTS
#include "ps/Vector2D.h"
class CBoundingBox;
class CBoundingCircle;
class CBoundingObject
{
public:
CBoundingObject() {}
virtual ~CBoundingObject() {}
enum EBoundingType
{
BOUND_NONE,
BOUND_CIRCLE,
BOUND_OABB
};
EBoundingType m_type;
CVector2D m_pos;
float m_radius;
float m_height;
void SetPosition( float x, float y );
void SetHeight( float height );
bool Intersects( CBoundingObject* obj );
bool Contains( const CVector2D& point );
virtual bool LooselyIntersects( CBoundingObject* obj, const CVector2D& delta ) = 0;
virtual bool LooselyContains( const CVector2D& point, const CVector2D& delta ) = 0;
virtual void Render( float height ) = 0; // Temporary
};
class CBoundingCircle : public CBoundingObject
{
public:
CBoundingCircle() { m_type = BOUND_OABB; }
CBoundingCircle( float x, float y, float radius, float height );
CBoundingCircle( float x, float y, CBoundingCircle* copy );
void SetRadius( float radius );
bool LooselyIntersects( CBoundingObject* obj, const CVector2D& delta );
bool LooselyContains( const CVector2D& point, const CVector2D& delta );
void Render( float height ); // Temporary
};
class CBoundingBox : public CBoundingObject
{
public:
CBoundingBox() { m_type = BOUND_OABB; }
CVector2D m_u; // Unit vector along the direction of this box's depth.
CVector2D m_v; // Unit vector along the direction of this box's width.
float m_d; // Half this box's depth.
float m_w; // Half this box's width.
CBoundingBox( float x, float y, float orientation, float width, float depth, float height );
CBoundingBox( float x, float y, const CVector2D& orientation, float width, float depth, float height );
CBoundingBox( float x, float y, float orientation, CBoundingBox* copy );
CBoundingBox( float x, float y, const CVector2D& orientation, CBoundingBox* copy );
void SetDimensions( float width, float depth );
void SetOrientation( float orientation );
void SetOrientation( const CVector2D& orientation );
float GetWidth() const { return( 2.0f * m_w ); };
float GetDepth() const { return( 2.0f * m_d ); };
bool LooselyIntersects( CBoundingObject* obj, const CVector2D& delta );
bool LooselyContains( const CVector2D& point, const CVector2D& delta );
void Render( float height ); // Temporary
};
#endif

View File

@ -1,317 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Collision.h"
#include "Entity.h"
#include "EntityManager.h"
#include "EntityTemplate.h"
#include <float.h>
CBoundingObject* GetContainingObject( const CVector2D& point )
{
std::vector<CEntity*> entities;
g_EntityManager.GetInRange( point.x, point.y, COLLISION_RANGE, entities );
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds->Contains( point ) )
{
CBoundingObject* bounds = (*it)->m_bounds;
return( bounds );
}
}
return( NULL );
}
CEntity* GetCollisionObject( float x, float y )
{
CVector2D point( x, y );
std::vector<CEntity*> entities;
g_EntityManager.GetInRange( x, y, COLLISION_RANGE, entities );
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds->Contains( point ) )
{
CEntity* e = (*it);
return( e );
}
}
return( NULL );
}
CBoundingObject* GetCollisionObject( CBoundingObject* bounds, CPlayer* player, const CStrW* ignoreClass )
{
std::vector<CEntity*> entities;
g_EntityManager.GetInRange( bounds->m_pos.x, bounds->m_pos.y, COLLISION_RANGE, entities );
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds == bounds ) continue;
/* If the unit is marked to ignore ally collisions, and the player parameter
is passed in and the same player as the unit, then ignore the (potential) collision */
if( player && (*it)->m_base->m_passThroughAllies && (*it)->GetPlayer() == player ) continue;
if( ignoreClass && (*it)->m_classes.IsMember( *ignoreClass ) ) continue;
if( bounds->Intersects( (*it)->m_bounds ) )
{
CBoundingObject* obj = (*it)->m_bounds;
return( obj );
}
}
return( NULL );
}
CEntity* GetCollisionEntity( CBoundingObject* bounds, CPlayer* player, const CStrW* ignoreClass )
{
std::vector<CEntity*> entities;
g_EntityManager.GetInRange( bounds->m_pos.x, bounds->m_pos.y, COLLISION_RANGE, entities );
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds == bounds ) continue;
/* If the unit is marked to ignore ally collisions, and the player parameter
is passed in and the same player as the unit, then ignore the (potential) collision */
if( player && (*it)->m_base->m_passThroughAllies && (*it)->GetPlayer() == player ) continue;
if( ignoreClass && (*it)->m_classes.IsMember( *ignoreClass ) ) continue;
if( bounds->Intersects( (*it)->m_bounds ) )
{
return (*it);
}
}
return( NULL );
}
HEntity GetCollisionObject( CEntity* entity, bool enablePassThroughAllies )
{
#ifndef NDEBUG
debug_assert( entity->m_bounds );
#else
if( !entity->m_bounds ) return HEntity();
#endif
std::vector<CEntity*> entities;
g_EntityManager.GetInRange( entity->m_position.X, entity->m_position.Z, COLLISION_RANGE, entities );
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds == entity->m_bounds ) continue;
if( enablePassThroughAllies
&& entity->m_base->m_passThroughAllies
&& (*it)->m_base->m_passThroughAllies
&& entity->GetPlayer() == (*it)->GetPlayer() )
continue;
if( entity->m_bounds->Intersects( (*it)->m_bounds ) )
{
HEntity collisionObject = HEntity((*it)->me);
return( collisionObject );
}
}
return HEntity();
}
HEntity GetCollisionObject( CEntity* entity, float x, float y )
{
float _x = entity->m_bounds->m_pos.x;
float _y = entity->m_bounds->m_pos.y;
entity->m_bounds->SetPosition( x, y );
HEntity _e = GetCollisionObject( entity );
entity->m_bounds->SetPosition( _x, _y );
return( _e );
}
bool GetRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results )
{
std::vector<CEntity*> entities;
g_EntityManager.GetExtant( entities );
std::vector<CEntity*>::iterator it;
float closestApproach, dist;
CVector2D delta;
results->distance = length + maxDistance;
results->boundingObject = NULL;
for( it = entities.begin(); it != entities.end(); it++ )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds == destinationCollisionObject ) continue;
// TODO MT: Replace this with something based on whether the unit is actually moving.
if( (*it)->m_orderQueue.size() ) continue;
CBoundingObject* obj = (*it)->m_bounds;
delta = obj->m_pos - source;
closestApproach = delta.Dot( right );
dist = delta.Dot( forward );
float collisionRadius = maxDistance + obj->m_radius;
if( ( fabs( closestApproach ) < collisionRadius ) && ( dist > collisionRadius * 0.0f ) && ( dist < length - collisionRadius * 0.0f ) )
{
if( dist < results->distance )
{
results->boundingObject = obj;
results->closestApproach = closestApproach;
results->distance = dist;
results->Entity = (*it);
results->position = obj->m_pos;
}
}
}
if( results->boundingObject ) return( true );
return( false );
}
void GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length, RayIntersects& results )
{
results.clear();
std::vector<CEntity*> entities;
g_EntityManager.GetExtant( entities );
float dist, closestApproach, l;
CVector2D delta;
std::vector<CEntity*>::iterator it;
for( it = entities.begin(); it != entities.end(); it++ )
{
CBoundingObject* obj = (*it)->m_bounds;
if( !obj ) continue;
delta = obj->m_pos - position;
closestApproach = delta.betadot( axis );
if( fabs( closestApproach ) > obj->m_radius )
continue; // Safe, doesn't get close enough.
dist = delta.Dot( axis );
// I just want to see if this will work before I simplify the maths
l = sqrt( obj->m_radius * obj->m_radius - closestApproach * closestApproach );
if( dist > 0 )
{
// Forward...
if( ( dist - length ) > l )
continue; // OK, won't reach it.
}
else
{
// Backward...
if( -dist > l )
continue; // OK, started far enough away
}
if( obj->m_type == CBoundingObject::BOUND_OABB )
{
// Run a more accurate test against the box
CBoundingBox* box = (CBoundingBox*)obj;
const float EPSILON = 0.0001f;
float first = FLT_MAX, last = -FLT_MAX;
CVector2D delta2;
// Test against those sides of the box parallel with it's u vector.
float t = box->m_u.y * axis.x - axis.y * box->m_u.x;
float abs_t = fabs( t );
if( abs_t >= EPSILON )
{
// If not parallel,
delta2 = delta - box->m_v * box->m_w;
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t )
{
// Possible intersection with one side
float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t;
if( pos < first ) first = pos;
if( pos > last ) last = pos;
}
delta2 = delta + box->m_v * box->m_w;
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t )
{
// Possible intersection with one side
float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t;
if( pos < first ) first = pos;
if( pos > last ) last = pos;
}
}
// Next test against those sides of the box parallel with it's v vector.
t = box->m_v.y * axis.x - axis.y * box->m_v.x;
abs_t = fabs( t );
if( abs_t >= EPSILON )
{
// If not parallel,
delta2 = delta - box->m_u * box->m_d;
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t )
{
// Possible intersection with one side
float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t;
if( pos < first ) first = pos;
if( pos > last ) last = pos;
}
delta2 = delta + box->m_u * box->m_d;
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t )
{
// Possible intersection with one side
float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t;
if( pos < first ) first = pos;
if( pos > last ) last = pos;
}
}
// Then work out if we actually hit it within the given range.
if( last < 0.0f )
continue; // No, we started far enough 'after' there.
if( first > length )
continue; // No, we haven't yet moved far enough to hit it.
}
results.push_back( *it );
}
}
static RayIntersects SharedResults;
RayIntersects& GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length )
{
GetProjectileIntersection( position, axis, length, SharedResults );
return( SharedResults );
}

View File

@ -1,67 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// Collision.h
//
// Collision detection functions
//
// Usage: Fairly trivial; GetCollisionObject( CEntity* entity ) will return the first entity colliding with the given entity.
// The version with (x, y) parameters is just a helper; it temporarily moves the entity's collision bounds to the given
// position before transferring to the other function.
// Notes: GetCollisionObject will only return the /first/ entity it finds in collision. This /may/ need a rethink when
// multiple-entity (pileup) collisions become possible, I don't know.
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#ifndef INCLUDED_COLLISION
#define INCLUDED_COLLISION
#include "BoundingObjects.h"
class CEntity;
class CPlayer;
class CStrW;
#include "EntityHandles.h"
struct rayIntersectionResults
{
CEntity* Entity;
CBoundingObject* boundingObject;
CVector2D position;
float closestApproach;
float distance;
};
// maximum radius at which we check for entities (if some entity is much bigger than this, that's bad)
#define COLLISION_RANGE 20
typedef std::vector<CEntity*> RayIntersects;
HEntity GetCollisionObject( CEntity* entity, bool enablePassThroughAllies=true );
HEntity GetCollisionObject( CEntity* entity, float x, float y );
CBoundingObject* GetCollisionObject( CBoundingObject* bounds, CPlayer* player=0, const CStrW* ignoreClass=0 );
CEntity* GetCollisionEntity( CBoundingObject* bounds, CPlayer* player=0, const CStrW* ignoreClass=0 );
CBoundingObject* GetContainingObject( const CVector2D& point );
CEntity* GetCollisionObject( float x, float y ); // Point collision
bool GetRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results );
// Assumes zero width, also includes moving units (other one doesn't).
void GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length, RayIntersects& results );
// Stores results in shared area
RayIntersects& GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length );
#endif

View File

@ -26,7 +26,6 @@
#include "maths/MathUtil.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/Game.h"
#include "ps/Interact.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
@ -299,12 +298,12 @@ void CEntity::Kill(bool keepActor)
removeObstacle();
g_Selection.RemoveAll( me );
// g_Selection.RemoveAll( me );
g_EntityManager.m_refd[me.m_handle] = false; // refd must be made false when DESTROYED is set
g_EntityManager.SetDeath(true); // remember that a unit died this frame
g_EntityManager.RemoveUnitCount(this); //Decrease population
// g_EntityManager.m_refd[me.m_handle] = false; // refd must be made false when DESTROYED is set
// g_EntityManager.SetDeath(true); // remember that a unit died this frame
//
// g_EntityManager.RemoveUnitCount(this); //Decrease population
// If we have a death animation and want to keep the actor, play that animation
if( keepActor && m_actor &&
@ -647,40 +646,7 @@ void CEntity::UpdateOrders( int timestep )
void CEntity::UpdateCollisionPatch()
{
std::vector<CEntity*>* newPatch = g_EntityManager.GetCollisionPatch( this );
if( newPatch != m_collisionPatch )
{
if( m_collisionPatch )
{
// remove ourselves from old patch
std::vector<CEntity*>& old = *m_collisionPatch;
if( old.size() == 1 )
{
// we were the only ones there, just pop us
old.pop_back();
}
else
{
// find our location and put in the last guy in the patch, then pop back
for( size_t i=0; i < old.size(); i++ )
{
if( old[i] == this )
{
old[i] = old.back();
old.pop_back();
break;
}
}
}
}
if( newPatch )
{
// add ourselves to new patch
newPatch->push_back( this );
m_collisionPatch = newPatch;
}
}
}
#if AURA_TEST
@ -803,29 +769,6 @@ void UpdateAuras_Normal( SAura& aura, CEntity* e )
bool CEntity::Initialize()
{
// Apply our player's active techs to ourselves (we do this here since m_player isn't yet set in the constructor)
const std::vector<CTechnology*>& techs = m_player->GetActiveTechs();
for( size_t i=0; i<techs.size(); i++ )
{
techs[i]->Apply( this );
}
// Dispatch the initialize script event
CEventInitialize evt;
if( !DispatchEvent( &evt ) )
{
//debug_printf(L"start construction failed, killing self\n");
Kill();
return false;
}
if( g_EntityManager.m_screenshotMode )
{
// Stay in Hold stance no matter what the init script wanted us to be
m_stanceName = "hold";
StanceChanged();
}
return true;
}
@ -1009,6 +952,7 @@ void CEntity::StanceChanged()
void CEntity::CheckSelection()
{
/*
if( m_selected )
{
if( !g_Selection.IsSelected( me ) )
@ -1019,13 +963,16 @@ void CEntity::CheckSelection()
if( g_Selection.IsSelected( me ) )
g_Selection.RemoveSelection( me );
}
*/
}
void CEntity::CheckGroup()
{
/*
g_Selection.ChangeGroup( me, -1 ); // Ungroup
if( ( m_grouped >= 0 ) && ( m_grouped < MAX_GROUPS ) )
g_Selection.ChangeGroup( me, m_grouped );
*/
}
void CEntity::Interpolate( float relativeoffset )

View File

@ -517,8 +517,6 @@ public:
int GetAttackAction( HEntity target );
};
typedef CJSCollection<HEntity, &CEntity::JSI_class> EntityCollection;
// General entity globals

View File

@ -24,7 +24,6 @@
#include "FormationManager.h"
#include "Simulation.h"
#include "ps/Game.h"
#include "ps/Interact.h"
#include "network/NetMessage.h"
CEntityFormation::CEntityFormation( CFormation*& base, size_t index )
@ -204,8 +203,10 @@ void CEntityFormation::SelectAllUnits() const
{
for ( size_t i=0; i<m_base->m_numSlots; ++i )
{
/*
if ( m_entities[i] && !g_Selection.IsSelected(m_entities[i]->me) )
g_Selection.AddSelection( m_entities[i]->me );
*/
}
}

View File

@ -1,206 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EntityHandles.h"
#include "EntityManager.h"
#include "Entity.h"
#include "ps/CStr.h"
#include "network/Serialization.h"
CHandle::CHandle()
{
m_entity = NULL;
m_refcount = 0;
}
HEntity::HEntity( size_t index )
{
m_handle = (u16)index;
AddRef();
}
HEntity::HEntity( const HEntity& copy )
{
m_handle = copy.m_handle;
AddRef();
}
HEntity::HEntity()
{
m_handle = INVALID_HANDLE;
}
HEntity::~HEntity()
{
if( CEntityManager::IsExtant() )
DecRef();
}
void HEntity::operator=( const HEntity& copy )
{
DecRef();
m_handle = copy.m_handle;
AddRef();
}
bool HEntity::operator ==( const HEntity& test ) const
{
return( m_handle == test.m_handle );
}
bool HEntity::IsValid() const
{
if( m_handle == INVALID_HANDLE )
return( false );
debug_assert( g_EntityManager.m_entities[m_handle].m_refcount );
//return( !g_EntityManager.m_entities[m_handle].m_entity->entf_get(ENTF_DESTROYED) );
return( true );
}
bool HEntity::IsAlive() const
{
return( IsValid() && !g_EntityManager.m_entities[m_handle].m_entity->entf_get(ENTF_DESTROYED) );
}
void HEntity::AddRef()
{
if( m_handle != INVALID_HANDLE )
{
debug_assert( m_handle < MAX_HANDLES );
g_EntityManager.m_entities[m_handle].m_refcount++;
g_EntityManager.m_refd[m_handle] = true;
}
}
void HEntity::DecRef()
{
if( m_handle != INVALID_HANDLE )
{
if( --g_EntityManager.m_entities[m_handle].m_refcount == 0 )
{
g_EntityManager.m_refd[m_handle] = false;
g_EntityManager.Destroy( m_handle );
}
}
}
CEntity* HEntity::operator->() const
{
debug_assert( m_handle != INVALID_HANDLE );
debug_assert( g_EntityManager.m_entities[m_handle].m_refcount );
return( g_EntityManager.m_entities[m_handle].m_entity );
}
HEntity::operator CEntity*() const
{
if( m_handle == INVALID_HANDLE )
return( NULL );
debug_assert( g_EntityManager.m_entities[m_handle].m_refcount );
return( g_EntityManager.m_entities[m_handle].m_entity );
}
CEntity& HEntity::operator*() const
{
debug_assert( m_handle != INVALID_HANDLE );
debug_assert( g_EntityManager.m_entities[m_handle].m_refcount );
return( *g_EntityManager.m_entities[m_handle].m_entity );
}
size_t HEntity::GetSerializedLength() const
{
return 2;
}
u8 *HEntity::Serialize(u8* buffer) const
{
Serialize_int_2(buffer, m_handle);
return buffer;
}
const u8* HEntity::Deserialize(const u8* buffer, const u8* UNUSED(end))
{
Deserialize_int_2(buffer, m_handle);
// We can't let AddRef debug_assert just because someone sent us bogus data
if (m_handle < MAX_HANDLES && m_handle != INVALID_HANDLE)
AddRef();
return buffer;
}
HEntity::operator CStr() const
{
char buf[16];
sprintf_s(buf, ARRAY_SIZE(buf), "Entity#%04x", m_handle);
return CStr(buf);
}
size_t CEntityList::GetSerializedLength() const
{
return (size_t)(2*(size()+1));
}
u8 *CEntityList::Serialize(u8 *buffer) const
{
Serialize_int_2(buffer, size());
for (size_t i=0; i<size(); i++)
Serialize_int_2(buffer, at(i).m_handle);
return buffer;
}
const u8 *CEntityList::Deserialize(const u8* buffer, const u8* UNUSED(end))
{
const int MAX_SIZE = 500; // TODO: Don't allow selecting more than this many entities
u16 size, handle;
Deserialize_int_2(buffer, size);
debug_assert(size > 0 && size < MAX_SIZE && "Inalid size when deserializing CEntityList");
for (int i=0; i<size; i++)
{
Deserialize_int_2(buffer, handle);
// We have to validate the data, or the HEntity constructor will debug_assert
// on us.
// FIXME We should also check that the entity actually exists
if (handle < MAX_HANDLES)
push_back(HEntity(handle));
}
return buffer;
}
CEntityList::operator CStr() const
{
if (size() == 0)
{
return CStr("Entities {}");
}
else if (size() == 1)
{
return front().operator CStr();
}
else
{
CStr buf="{ ";
buf += front().operator CStr();
for (const_iterator it=begin();it != end();++it)
{
buf += ", ";
buf += it->operator CStr();
}
buf += " }";
return buf;
}
}

View File

@ -1,130 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// EntityHandles.h
//
// Entity smart pointer definitions.
//
// Usage: Use in place of a standard CEntity pointer.
// Handles dereference and pointer-to-member as a standard smart pointer.
// Reference counted. Handles are freed and entity classes released when refcount hits 0.
// For this reason, be careful where and how long you store these.
//
// Entities maintain their own handles via their HEntity me member.
// To release an entity, scramble this handle. The memory will be freed when the last reference to it expires.
//
// Standard CEntity pointers must not be used for a) anything that could be sent over the network.
// b) anything that will be kept between simulation steps.
// CEntity pointers will be faster for passing to the graphics subsytem, etc. where they won't be stored.
// And yes, most of this /is/ obvious. But it should be said anyway.
#ifndef INCLUDED_ENTITYHANDLES
#define INCLUDED_ENTITYHANDLES
#define INVALID_HANDLE 65535
class CEntity;
class CEntityManager;
struct CEntityList;
class CStr8;
class CHandle
{
public:
CEntity* m_entity;
i16 m_refcount;
CHandle();
};
class HEntity
{
friend class CEntity;
friend class CEntityManager;
friend struct CEntityList;
u16 m_handle;
private:
void AddRef();
void DecRef();
HEntity( size_t index );
public:
HEntity();
HEntity( const HEntity& copy );
~HEntity();
void operator=( const HEntity& copy );
CEntity& operator*() const;
CEntity* operator->() const;
bool operator==( const HEntity& test ) const;
bool operator!=( const HEntity& test ) const { return( !operator==( test ) ); }
operator CEntity*() const;
// Returns true iff we are a valid handle, i.e. one to a non-deleted (but possibly destroyed) entity
bool IsValid() const;
// Returns true iff we are a valid handle to an entity that is not destroyed
bool IsAlive() const;
// Same as IsValid(); maybe this should be removed altogether to prevent confusion?
operator bool() const { return IsValid(); }
// Same as !IsValid()
bool operator!() const { return !IsValid(); };
size_t GetSerializedLength() const;
u8 *Serialize(u8 *buffer) const;
const u8 *Deserialize(const u8 *buffer, const u8 *end);
operator CStr8() const;
};
/*
CEntityList
DESCRIPTION: Represents a group of entities that is the target/subject of
a network command. Use for easy serialization of one or more entity IDs.
SERIALIZED FORMAT: The entities are stored as a sequence of 16-bit ints, the
termination of the list marked by an integer with HANDLE_SENTINEL_BIT
set. The length is thus 2*(number of entities)
*/
struct CEntityList: public std::vector<HEntity>
{
// Create an empty list
inline CEntityList()
{}
// Create a list from an existing entity vector
inline CEntityList(const std::vector<HEntity> &vect):
std::vector<HEntity>(vect)
{}
// Create a list containing one entity
inline CEntityList(HEntity oneEntity)
{
push_back(oneEntity);
}
size_t GetSerializedLength() const;
u8 *Serialize(u8 *buffer) const;
const u8 *Deserialize(const u8 *buffer, const u8 *end);
operator CStr8() const;
};
typedef CEntityList::iterator CEntityIt;
typedef CEntityList::const_iterator CEntityCIt;
#endif

View File

@ -1,521 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EntityManager.h"
#include "EntityTemplateCollection.h"
#include "EntityTemplate.h"
#include "ps/ConfigDB.h"
#include "ps/Player.h"
#include "ps/Profile.h"
#include "graphics/Terrain.h"
#include "ps/Game.h"
#include "maths/MathUtil.h"
#include "Entity.h"
#include "lib/timer.h"
#ifdef USE_DCDT
# include "dcdt/se/se_dcdt.h"
#endif // USE_DCDT
#include "PathfindEngine.h"
#include "ps/GameSetup/Config.h"
int AURA_CIRCLE_POINTS;
int SELECTION_CIRCLE_POINTS;
int SELECTION_BOX_POINTS;
int SELECTION_SMOOTHNESS_UNIFIED = 9;
CEntityManager::CEntityManager()
: m_collisionPatches(0)
, m_screenshotMode(false)
, m_entities() // janwas: default-initialize entire array;
// CHandle ctor sets m_entity and m_refcount to 0
{
m_nextalloc = 0;
m_extant = true;
m_death = false;
// Also load a couple of global entity settings
CConfigValue* cfg = g_ConfigDB.GetValue( CFG_USER, "selection.outline.quality" );
if( cfg ) cfg->GetInt( SELECTION_SMOOTHNESS_UNIFIED );
if( SELECTION_SMOOTHNESS_UNIFIED < 0 ) SELECTION_SMOOTHNESS_UNIFIED = 0;
SELECTION_CIRCLE_POINTS = 7 + 2 * SELECTION_SMOOTHNESS_UNIFIED;
SELECTION_BOX_POINTS = 1 + SELECTION_SMOOTHNESS_UNIFIED;
AURA_CIRCLE_POINTS = 7 + 3 * SELECTION_SMOOTHNESS_UNIFIED;
}
void CEntityManager::DeleteAllHelper()
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
{
if( m_entities[i].m_refcount )
{
delete( m_entities[i].m_entity );
m_entities[i].m_entity = 0;
m_entities[i].m_refcount = 0;
m_refd[i] = false;
}
}
}
CEntityManager::~CEntityManager()
{
m_extant = false;
DeleteAllHelper();
// Delete entities that were killed, but not yet reaped by a call to UpdateAll,
// to avoid memory leak warnings upon exiting
std::vector<CEntity*>::iterator it;
for( it = m_reaper.begin(); it < m_reaper.end(); it++ )
delete( *it );
m_reaper.clear();
delete[] m_collisionPatches;
m_collisionPatches = NULL;
}
void CEntityManager::DeleteAll()
{
m_extant = false;
DeleteAllHelper();
m_nextalloc = 0;
delete[] m_collisionPatches;
m_collisionPatches = NULL;
m_extant = true;
}
void CEntityManager::updateObstacle( CEntity* tempHandle )
{
(void)tempHandle;
#ifdef USE_DCDT
if(g_Pathfinder.dcdtInitialized)
{
SrPolygon poly;
poly.size(0);
CVector2D p, q;
CVector2D u, v;
q.x = tempHandle->m_position.X;
q.y = tempHandle->m_position.Z;
float d = ((CBoundingBox*)tempHandle->m_bounds)->m_d;
float w = ((CBoundingBox*)tempHandle->m_bounds)->m_w;
u.x = sin( tempHandle->m_graphics_orientation.Y );
u.y = cos( tempHandle->m_graphics_orientation.Y );
v.x = u.y;
v.y = -u.x;
CBoundingObject* m_bounds = tempHandle->m_bounds;
switch( m_bounds->m_type )
{
case CBoundingObject::BOUND_CIRCLE:
{
if(tempHandle->m_speed == 0)
{
poly.open(false);
w = 0.5;
d = 0.5;
p = q + u * d + v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d + v * w ;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q + u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
int dcdtId = g_Pathfinder.dcdtPathfinder.insert_polygon(poly);
tempHandle->m_dcdtId = dcdtId;
}
break;
}
case CBoundingObject::BOUND_OABB:
{
poly.open(false);
// Tighten the bound so the units will not get stuck near the buildings
//Note: the triangulation pathfinding code will not find a path for the unit if it is pushed into the bound of a unit.
//
w = w * 0.8;
d = d * 0.8;
p = q + u * d + v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d + v * w ;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q + u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
int dcdtId = g_Pathfinder.dcdtPathfinder.insert_polygon(poly);
tempHandle->m_dcdtId = dcdtId;
break;
}
}//end switch
g_Pathfinder.dcdtPathfinder.DeleteAbstraction();
g_Pathfinder.dcdtPathfinder.Abstract();
if(g_ShowPathfindingOverlay)
{
g_Pathfinder.drawTriangulation();
}
}
#endif // USE_DCDT
}
HEntity CEntityManager::Create(CEntityTemplate* base, CVector3D position, float orientation,
const std::set<CStr>& actorSelections, const CStrW* building)
{
debug_assert( base );
if( !base )
return HEntity();
// Find an unused handle for the unit
size_t pos = 0;
while( m_entities[m_nextalloc].m_refcount )
{
m_nextalloc++;
if(m_nextalloc >= MAX_HANDLES)
{
debug_warn(L"Ran out of entity handles!");
return HEntity();
}
}
pos = m_nextalloc;
m_nextalloc++;
debug_assert(m_entities[pos].m_entity == 0);
m_entities[pos].m_entity = new CEntity( base, position, orientation, actorSelections, building );
if( m_collisionPatches)
m_entities[pos].m_entity->UpdateCollisionPatch();
m_entities[pos].m_entity->me = HEntity( pos );
//Kai: invoking triangulation update for new objects
updateObstacle(m_entities[pos].m_entity);
return( HEntity( pos ) );
}
void CEntityManager::AddEntityClassData(const HEntity& handle)
{
//Add data for this particular entity and player
size_t playerID = handle->GetPlayer()->GetPlayerID();
CStrW className, classList = handle->m_classes.GetMemberList();
while ( (className = classList.BeforeFirst(L" ")) != classList )
{
if ( m_entityClassData[playerID].find(className) == m_entityClassData[playerID].end() )
m_entityClassData[playerID][className] = 0;
++m_entityClassData[playerID][className];
classList = classList.AfterFirst(L" ");
}
//For last element
if ( m_entityClassData[playerID].find(className) == m_entityClassData[playerID].end() )
m_entityClassData[playerID][className] = 0;
++m_entityClassData[playerID][className];
}
HEntity CEntityManager::Create( const CStrW& templateName, CPlayer* player, CVector3D position, float orientation, const CStrW* building )
{
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate( templateName, player );
debug_assert( base );
if( !base )
return HEntity();
std::set<CStr> selections;
HEntity ret = Create( base, position, orientation, selections, building );
AddEntityClassData(ret);
return ret;
}
HEntity CEntityManager::CreateFoundation( const CStrW& templateName, CPlayer* player, CVector3D position, float orientation )
{
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate( templateName, player );
debug_assert( base );
if( !base )
return HEntity();
std::set<CStr> selections;
if( base->m_foundation == L"" )
return Create( base, position, orientation, selections ); // Entity has no foundation, so just create it
// Else, place the foundation object, telling it to convert into the right template when built.
CEntityTemplate* foundation = g_EntityTemplateCollection.GetTemplate( base->m_foundation );
return Create( foundation, position, orientation, selections, &templateName );
}
HEntity* CEntityManager::GetByHandle( size_t index )
{
if( index >= MAX_HANDLES ) return( NULL );
if( !m_entities[index].m_refcount ) return( NULL );
return( new HEntity( index ) );
}
CHandle *CEntityManager::GetHandle( size_t index )
{
if (!m_entities[index].m_refcount )
return NULL;
return &m_entities[index];
}
void CEntityManager::GetMatchingAsHandles(std::vector<HEntity>& matchlist, EntityPredicate predicate, void* userdata)
{
matchlist.clear();
for( size_t i = 0; i < MAX_HANDLES; i++ )
{
if( IsEntityRefd(i) )
if( predicate( m_entities[i].m_entity, userdata ) )
matchlist.push_back( HEntity( i ) );
}
}
void CEntityManager::GetExtantAsHandles( std::vector<HEntity>& results )
{
results.clear();
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) )
results.push_back( HEntity( i ) );
}
void CEntityManager::GetExtant( std::vector<CEntity*>& results )
{
results.clear();
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) )
results.push_back( m_entities[i].m_entity );
}
void CEntityManager::GetInRange( float x, float z, float radius, std::vector<CEntity*>& results )
{
results.clear();
float radiusSq = radius * radius;
int cx = (int) ( x / COLLISION_PATCH_SIZE );
int cz = (int) ( z / COLLISION_PATCH_SIZE );
int r = (int) ( radius / COLLISION_PATCH_SIZE + 1 );
int minX = std::max(cx-r, 0);
int minZ = std::max(cz-r, 0);
int maxX = std::min(cx+r, m_collisionPatchesPerSide-1);
int maxZ = std::min(cz+r, m_collisionPatchesPerSide-1);
for( int px = minX; px <= maxX; px++ )
{
for( int pz = minZ; pz <= maxZ; pz++ )
{
std::vector<CEntity*>& vec = m_collisionPatches[ px * m_collisionPatchesPerSide + pz ];
for( size_t i=0; i<vec.size(); i++ )
{
CEntity* e = vec[i];
debug_assert(e != 0);
float dx = x - e->m_position.X;
float dz = z - e->m_position.Z;
if( dx*dx + dz*dz <= radiusSq )
{
results.push_back( e );
}
}
}
}
}
void CEntityManager::GetInLOS( CEntity* entity, std::vector<CEntity*>& results )
{
GetInRange( entity->m_position.X, entity->m_position.Z, entity->m_los*CELL_SIZE, results );
}
/*
void CEntityManager::dispatchAll( CMessage* msg )
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( m_entities[i].m_refcount && m_entities[i].m_entity->m_extant )
m_entities[i].m_entity->dispatch( msg );
}
*/
TIMER_ADD_CLIENT(tc_1);
TIMER_ADD_CLIENT(tc_2);
void CEntityManager::InitializeAll()
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
int unitsPerSide = CELL_SIZE * ( terrain->GetVerticesPerSide() - 1 );
m_collisionPatchesPerSide = unitsPerSide / COLLISION_PATCH_SIZE + 1;
debug_assert(! m_collisionPatches);
m_collisionPatches = new std::vector<CEntity*>[m_collisionPatchesPerSide * m_collisionPatchesPerSide];
for( size_t i = 0; i < MAX_HANDLES; i++ )
{
if( IsEntityRefd(i) )
{
// [2006-06-26 2780ms total]
CEntity* e = m_entities[i].m_entity;
e->Initialize();
// [2006-06-26 8ms total]
e->UpdateCollisionPatch();
}
}
}
/*
void CEntityManager::TickAll()
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) && m_entities[i].m_entity->m_extant )
m_entities[i].m_entity->Tick();
}
*/
void CEntityManager::UpdateAll( int timestep )
{
PROFILE_START( "reaper" );
std::vector<CEntity*>::iterator it;
for( it = m_reaper.begin(); it < m_reaper.end(); it++ )
delete( *it );
m_reaper.clear();
PROFILE_END( "reaper" );
// PT: TickAll (which sends the 'Tick' event to all entities) has been
// disabled, because:
// * it's very slow (particularly when there are thousands of entities, e.g. trees);
// * no entity currently responds to tick events;
// * nobody can think of a situation where ticks would be required in the future;
// * if they ever are needed, they can be done more efficiently (e.g. by
// adding a per-entity 'wants tick' flag);
// * it's very slow.
/*
PROFILE_START( "tick all" );
TickAll();
PROFILE_END( "tick all" );
*/
PROFILE_START( "update all" );
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) )
m_entities[i].m_entity->Update( timestep );
PROFILE_END( "update all" );
}
void CEntityManager::InterpolateAll( float relativeoffset )
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
// This needs to handle all entities, including destroyed/non-extant ones
// (mainly dead bodies), so it can't use IsEntityRefd
if( m_entities[i].m_refcount && m_entities[i].m_entity )
m_entities[i].m_entity->Interpolate( relativeoffset );
}
void CEntityManager::RenderAll()
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) )
m_entities[i].m_entity->Render();
}
void CEntityManager::ConformAll()
{
PROFILE_START("conform all");
for ( size_t i=0; i < MAX_HANDLES; i++ )
{
if( IsEntityRefd(i) )
{
m_entities[i].m_entity->UpdateXZOrientation();
m_entities[i].m_entity->UpdateActorTransforms();
}
}
PROFILE_END("conform all");
}
void CEntityManager::InvalidateAll()
{
for( size_t i = 0; i < MAX_HANDLES; i++ )
if( IsEntityRefd(i) )
m_entities[i].m_entity->InvalidateActor();
}
void CEntityManager::RemoveUnitCount(CEntity* ent)
{
size_t playerID = ent->GetPlayer()->GetPlayerID();
CStrW className, classList = ent->m_classes.GetMemberList();
while ( (className = classList.BeforeFirst(L" ")) != classList )
{
--m_entityClassData[playerID][className];
classList = classList.AfterFirst(L" ");
}
--m_entityClassData[playerID][className];
}
void CEntityManager::Destroy( size_t handle )
{
m_reaper.push_back( m_entities[handle].m_entity );
}
bool CEntityManager::m_extant = false;
std::vector<CEntity*>* CEntityManager::GetCollisionPatch( CEntity* e )
{
if( !e->m_extant )
{
return 0;
}
int ix = (int) ( e->m_position.X / COLLISION_PATCH_SIZE );
int iz = (int) ( e->m_position.Z / COLLISION_PATCH_SIZE );
return &m_collisionPatches[ ix * m_collisionPatchesPerSide + iz ];
}

View File

@ -1,154 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// EntityManager.h
//
// Maintains entity id->object mappings. Does most of the work involved in creating an entity.
//
// Usage: Do not attempt to directly instantiate an entity class.
// HEntity bob = g_EntityManager.Create( unit_class_name, position, orientation );
// or HEntity jim = g_EntityManager.Create( pointer_to_unit_class, position, orientation );
//
// Perform updates on all world entities by g_EntityManager.UpdateAll( timestep )
// Dispatch an identical message to all world entities by g_EntityManager.dispatchAll( message_pointer )
// Fill an STL vector container with all entities matching a certain predicate with g_EntityManager.GetMatchingAsHandles( container, predicate, data )
// or just get all entities with g_EntityManager.GetExtant().
//
// Those last two functions - caller has responsibility for deleting the collection when you're done with it.
#ifndef INCLUDED_ENTITYMANAGER
#define INCLUDED_ENTITYMANAGER
#include <set>
#include <bitset>
#include <map>
#include "EntityHandles.h"
#include "ps/Game.h"
#include "ps/World.h"
class CEntityTemplate;
class CPlayer;
class CStrW;
class CStr8;
class CVector3D;
const size_t MAX_HANDLES = 16384;
cassert(MAX_HANDLES < 0x10000);
// collision patch size, in graphics units, not tiles (1 tile = 4 units)
#define COLLISION_PATCH_SIZE 8
#define g_EntityManager g_Game->GetWorld()->GetEntityManager()
class CEntityManager
{
friend class CEntity;
friend class HEntity;
friend class CHandle;
CHandle m_entities[MAX_HANDLES];
std::bitset<MAX_HANDLES> m_refd;
std::vector<CEntity*> m_reaper;
std::vector<CEntity*>* m_collisionPatches;
size_t m_nextalloc;
static bool m_extant;
bool m_death;
int m_collisionPatchesPerSide;
//Optimized data for triggers. key = playerID, nested key = entity class, value = frequency
std::map<size_t, std::map<CStrW, int> > m_entityClassData;
void Destroy( size_t handle );
void DeleteAllHelper();
inline bool IsEntityRefd( size_t index )
{
if(!m_entities[index].m_entity)
return false;
return m_refd[index];
//return m_entities[index].m_refcount && !m_entities[index].m_entity->entf_get(ENTF_DESTROYED);
}
public:
bool m_screenshotMode;
CEntityManager();
~CEntityManager();
HEntity Create( CEntityTemplate* base, CVector3D position, float orientation,
const std::set<CStr8>& actorSelections, const CStrW* building = 0 );
HEntity Create( const CStrW& templateName, CPlayer* player, CVector3D position,
float orientation, const CStrW* building = 0 );
HEntity CreateFoundation( const CStrW& templateName, CPlayer* player, CVector3D position,
float orientation );
HEntity* GetByHandle( size_t index );
CHandle *GetHandle( size_t index );
inline int GetPlayerUnitCount( size_t player, const CStrW& name )
{
if ( m_entityClassData[player].find(name) == m_entityClassData[player].end() )
m_entityClassData[player][name] = 0;
return m_entityClassData[player][name];
}
void RemoveUnitCount(CEntity* ent); //Removes unit from population count
void AddEntityClassData(const HEntity& handle);
void UpdateAll( int timestep );
void InterpolateAll( float relativeoffset );
void InitializeAll();
// void TickAll();
void RenderAll();
void ConformAll();
void InvalidateAll();
void DeleteAll();
bool GetDeath() { return m_death; }
void SetDeath(bool set) { m_death=set; }
//Kai: added function to update the triangulation when entities are created
void updateObstacle(CEntity* tempHandle);
// Predicate functions
typedef bool (*EntityPredicate)( CEntity* target, void* userdata );
template<EntityPredicate left, EntityPredicate right> static bool EntityPredicateLogicalOr( CEntity* target, void* userdata )
{ return( left( target, userdata ) || right( target, userdata ) ); }
template<EntityPredicate left, EntityPredicate right> static bool EntityPredicateLogicalAnd( CEntity* target, void* userdata )
{ return( left( target, userdata ) && right( target, userdata ) ); }
template<EntityPredicate operand> static bool EntityPredicateLogicalNot( CEntity* target, void* userdata )
{ return( !operand( target, userdata ) ); }
void GetMatchingAsHandles( std::vector<HEntity>& matchlist, EntityPredicate predicate, void* userdata = 0 );
void GetExtantAsHandles( std::vector<HEntity>& results );
void GetExtant( std::vector<CEntity*>& results );
static inline bool IsExtant() // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped.
{
return( m_extant );
}
void GetInRange( float x, float z, float radius, std::vector<CEntity*>& results );
void GetInLOS( CEntity* entity, std::vector<CEntity*>& results );
std::vector<CEntity*>* GetCollisionPatch( CEntity* e );
};
#endif

View File

@ -1,164 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// EntityOrders.h
//
// Entity orders structure.
//
// Usage: All orders at this point use the location component of the union.
// Orders are: ORDER_GOTO_NOPATHING: Attempts to reach the given destination via a line-of-sight
// ORDER_GOTO_SMOOTED: system. Do not create an order of these types directly; it is
// used to return a path of line segments from the pathfinder.
// _SMOOTHED flags to the entity state-control that it's OK to
// smooth the corner between segments. _NOPATHING just does
// zero-radius turns.
// ORDER_GOTO_COLLISION: When the coldet system is trying to get us out of a collision,
// it generates these intermediate waypoints. We don't really have
// any reason to go to this specific point, so if a better way
// comes along, this order can be deleted.
// ORDER_GOTO: Attempts to reach the given destination. Uses the pathfinder
// to... er... find the path.
// Create this order when a standard movement or movement waypoint
// order is required.
// ORDER_PATROL: As ORDER_GOTO, but pushes the patrol order onto the back of the
// order queue after it's executed. In this way, the entity will
// circle round a list of patrol points.
// Create this order when a standard patrol order is required.
// ORDER_CONTACT_ACTION: Generic ranged action. Move towards target entity, then start
// performing an action (call a JS event handler every few seconds).
// If we collide with something (=> line-of-sight tracking no longer
// sufficient) spawns a ORDER_GOTO to target's location and pushes it
// immediately in front of this order.
//
// Entities which exhaust all orders from their queue go to idle status; there is no specific order
// type for this status.
#ifndef INCLUDED_ENTITYORDERS
#define INCLUDED_ENTITYORDERS
#define ORDER_MAX_DATA 2
#include "EntityHandles.h"
#include "ps/Vector2D.h"
#include "ps/CStr.h"
#include <deque>
class CEntityListener
{
public:
enum EType
{
NOTIFY_NONE = 0x00,
NOTIFY_GOTO = 0x01,
NOTIFY_RUN = 0x02,
NOTIFY_FOLLOW = 0x03, //GOTO | RUN
NOTIFY_ATTACK = 0x04,
NOTIFY_DAMAGE = 0x08,
NOTIFY_COMBAT = 0x0C, //ATTACK | DAMAGE
NOTIFY_ESCORT = 0x0F, //GOTO | ATTACK | DAMAGE
NOTIFY_HEAL = 0x10,
NOTIFY_GATHER = 0x20,
NOTIFY_IDLE = 0x40,
NOTIFY_ORDER_CHANGE = 0x80, //this isn't counted in NOTIFY_ALL
NOTIFY_ALL = 0x7F
} m_type;
CEntity* m_sender;
};
class CEntityOrder
{
public:
enum EOrderType
{
ORDER_INVALID, // 0
ORDER_GOTO_NOPATHING, // 1
ORDER_GOTO_NOPATHING_CONTACT, // 2
ORDER_GOTO_SMOOTHED, // 3
ORDER_GOTO_COLLISION, // 4
ORDER_GOTO_WAYPOINT, // 5
ORDER_GOTO_WAYPOINT_CONTACT, // 6
ORDER_GOTO, // 7
ORDER_RUN, // 8
ORDER_PATROL, // 9
ORDER_PATH_END_MARKER, // 10
ORDER_CONTACT_ACTION, // 11
ORDER_CONTACT_ACTION_NOPATHING, // 12
ORDER_PRODUCE, // 13
ORDER_START_CONSTRUCTION, // 14
ORDER_SET_RALLY_POINT, // 15
ORDER_SET_STANCE, // 16
ORDER_NOTIFY_REQUEST, // 17
ORDER_LAST // 18
};
EOrderType m_type;
enum EOrderSource
{
SOURCE_PLAYER,
SOURCE_UNIT_AI,
SOURCE_TRIGGERS
};
EOrderSource m_source;
// all commands involving pathfinder (i.e. all :P)
float m_pathfinder_radius;
// NMT_PLACE_OBJECT
HEntity m_new_obj;
// NMT_GOTO
// NMT_FORMATION_GOTO
// NMT_RUN
// NMT_PATROL
// NMT_ADD_WAYPOINT
CVector2D m_target_location;
// NMT_CONTACT_ACTION
// NMT_FORMATION_CONTACT_ACTION
// NMT_NOTIFY_REQUEST
HEntity m_target_entity;
int m_action;
// NMT_PRODUCE, NMT_SET_STANCE
CStrW m_name;
// NMT_PRODUCE
int m_produce_type;
// NMT_CONTACT_ACTION
bool m_run;
CEntityOrder(): m_type(ORDER_INVALID), m_source(SOURCE_PLAYER) {}
CEntityOrder(EOrderType type, EOrderSource source=SOURCE_PLAYER)
: m_type(type), m_source(source) {}
};
typedef std::deque<CEntityOrder> CEntityOrders;
typedef CEntityOrders::iterator CEntityOrderIt;
typedef CEntityOrders::const_iterator CEntityOrderCIt;
typedef CEntityOrders::const_reverse_iterator CEntityOrderCRIt;
#endif

View File

@ -27,8 +27,8 @@
#include "maths/MathUtil.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/Game.h"
#include "ps/Interact.h"
#include "ps/Profile.h"
#include "ps/Player.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "scripting/ScriptableComplex.inl"
@ -37,13 +37,11 @@
#include "Collision.h"
#include "Entity.h"
#include "EntityFormation.h"
#include "EntityManager.h"
#include "EntityTemplate.h"
#include "EntityTemplateCollection.h"
#include "EventHandlers.h"
#include "Formation.h"
#include "FormationManager.h"
#include "PathfindEngine.h"
#include "ProductionQueue.h"
#include "TechnologyCollection.h"
#include "TerritoryManager.h"
@ -391,8 +389,10 @@ void CEntity::RenderBars()
float backgroundW = w+2*borderSize;
float backgroundH = hasStamina ? 2*h+2*borderSize : h+2*borderSize;
/*
ogl_tex_bind( g_Selection.m_unitUITextures[m_base->m_barBorder] );
DrawRect( centre, up, right, -backgroundW/2, -backgroundH/2, backgroundW/2, backgroundH/2 );
*/
ogl_tex_bind( 0 );
float off = hasStamina ? h/2 : 0;
@ -407,6 +407,7 @@ void CEntity::RenderBars()
// Draw the rank icon
/*
CSelectedEntities::MapFilenameToHandle::iterator it = g_Selection.m_unitUITextures.find( m_rankName );
if( it != g_Selection.m_unitUITextures.end() )
{
@ -415,6 +416,7 @@ void CEntity::RenderBars()
DrawRect( centre, up, right, w/2+borderSize, -size/2, w/2+borderSize+size, size/2 );
ogl_tex_bind( 0 );
}
*/
}
void CEntity::RenderBarBorders()
@ -422,6 +424,7 @@ void CEntity::RenderBarBorders()
if( !m_visible )
return;
/*
if ( m_base->m_staminaBarHeight >= 0 &&
g_Selection.m_unitUITextures.find(m_base->m_healthBorderName) != g_Selection.m_unitUITextures.end() )
{
@ -464,6 +467,7 @@ void CEntity::RenderBarBorders()
glEnd();
}
*/
}
void CEntity::RenderHealthBar()
@ -544,8 +548,10 @@ void CEntity::RenderRank()
if( m_base->m_rankHeight < 0 )
return; // negative height means don't display rank
//Check for valid texture
/*
if( g_Selection.m_unitUITextures.find( m_rankName ) == g_Selection.m_unitUITextures.end() )
return;
*/
CCamera *camera = g_Game->GetView()->GetCamera();
@ -562,7 +568,7 @@ void CEntity::RenderRank()
float y1 = g_yres - (sy - size); //top
float y2 = g_yres - (sy + size); //bottom
ogl_tex_bind(g_Selection.m_unitUITextures[m_rankName]);
// ogl_tex_bind(g_Selection.m_unitUITextures[m_rankName]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
@ -582,11 +588,13 @@ void CEntity::RenderRallyPoint()
if( !m_visible )
return;
/*
if ( !entf_get(ENTF_HAS_RALLY_POINT) ||
g_Selection.m_unitUITextures.find(m_base->m_rallyName) == g_Selection.m_unitUITextures.end() )
{
return;
}
*/
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
@ -599,7 +607,7 @@ void CEntity::RenderRallyPoint()
CSprite sprite;
CTexture tex;
tex.SetHandle( g_Selection.m_unitUITextures[m_base->m_rallyName] );
// tex.SetHandle( g_Selection.m_unitUITextures[m_base->m_rallyName] );
sprite.SetTexture(&tex);
// Place the sprite slightly above ground/water level.
float terrainHeight = g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel(m_rallyPoint);

View File

@ -1,937 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "graphics/GameView.h"
#include "graphics/Model.h"
#include "graphics/Sprite.h"
#include "graphics/Terrain.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "maths/MathUtil.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/Game.h"
#include "ps/Interact.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "scripting/ScriptableComplex.inl"
#include "ps/scripting/JSCollection.h"
#include "network/NetMessage.h"
#include "Aura.h"
#include "Collision.h"
#include "Entity.h"
#include "EntityFormation.h"
#include "EntityManager.h"
#include "EntityTemplate.h"
#include "EntityTemplateCollection.h"
#include "EventHandlers.h"
#include "Formation.h"
#include "FormationManager.h"
#include "PathfindEngine.h"
#include "ProductionQueue.h"
#include "TechnologyCollection.h"
#include "TerritoryManager.h"
#include "Simulation.h"
#include "Stance.h"
#include <algorithm>
extern int g_xres, g_yres;
/*
Scripting interface
*/
// Scripting initialization
void CEntity::ScriptingInit()
{
// TODO: lots of these return jsval when they should return proper types
// and make use of automatic type conversion
AddMethod<jsval_t, &CEntity::ToString>( "toString", 0 );
AddMethod<bool, &CEntity::OrderSingle>( "order", 1 );
AddMethod<bool, &CEntity::OrderQueued>( "orderQueued", 1 );
AddMethod<bool, &CEntity::OrderFromTriggers>( "orderFromTriggers", 1 );
AddMethod<jsval_t, &CEntity::TerminateOrder>( "terminateOrder", 1 );
AddMethod<bool, &CEntity::Kill>( "kill", 0 );
AddMethod<bool, &CEntity::IsIdle>( "isIdle", 0 );
AddMethod<bool, &CEntity::IsDestroyed>( "isDestroyed", 0 );
AddMethod<bool, &CEntity::HasClass>( "hasClass", 1 );
AddMethod<jsval_t, &CEntity::GetSpawnPoint>( "getSpawnPoint", 1 );
AddMethod<jsval_t, &CEntity::AddAura>( "addAura", 3 );
AddMethod<jsval_t, &CEntity::RemoveAura>( "removeAura", 1 );
AddMethod<jsval_t, &CEntity::SetActionParams>( "setActionParams", 5 );
AddMethod<int, &CEntity::GetCurrentRequest>( "getCurrentRequest", 0 );
AddMethod<bool, &CEntity::ForceCheckListeners>( "forceCheckListeners", 2 );
AddMethod<bool, &CEntity::RequestNotification>( "requestNotification", 4 );
AddMethod<jsval_t, &CEntity::DestroyNotifier>( "destroyNotifier", 1 );
AddMethod<jsval_t, &CEntity::DestroyAllNotifiers>( "destroyAllNotifiers", 0 );
AddMethod<jsval_t, &CEntity::TriggerRun>( "triggerRun", 1 );
AddMethod<jsval_t, &CEntity::SetRun>( "setRun", 1 );
AddMethod<jsval_t, &CEntity::GetRunState>( "getRunState", 0 );
AddMethod<bool, &CEntity::IsInFormation>( "isInFormation", 0 );
AddMethod<jsval_t, &CEntity::GetFormationBonus>( "getFormationBonus", 0 );
AddMethod<jsval_t, &CEntity::GetFormationBonusType>( "getFormationBonusType", 0 );
AddMethod<jsval_t, &CEntity::GetFormationBonusVal>( "getFormationBonusVal", 0 );
AddMethod<jsval_t, &CEntity::GetFormationPenalty>( "getFormationPenalty", 0 );
AddMethod<jsval_t, &CEntity::GetFormationPenaltyType>( "getFormationPenaltyType", 0 );
AddMethod<jsval_t, &CEntity::GetFormationPenaltyVal>( "getFormationPenaltyVal", 0 );
AddMethod<jsval_t, &CEntity::RegisterDamage>( "registerDamage", 0 );
AddMethod<jsval_t, &CEntity::RegisterOrderChange>( "registerOrderChange", 0 );
AddMethod<jsval_t, &CEntity::GetAttackDirections>( "getAttackDirections", 0 );
AddMethod<jsval_t, &CEntity::FindSector>( "findSector", 4);
AddMethod<jsval_t, &CEntity::GetHeight>( "getHeight", 0 );
AddMethod<jsval_t, &CEntity::HasRallyPoint>( "hasRallyPoint", 0 );
AddMethod<jsval_t, &CEntity::SetRallyPointAtCursor>( "setRallyPointAtCursor", 0 );
AddMethod<jsval_t, &CEntity::GetRallyPoint>( "getRallyPoint", 0 );
AddMethod<jsval_t, &CEntity::OnDamaged>( "onDamaged", 1 );
AddMethod<jsval_t, &CEntity::GetVisibleEntities>( "getVisibleEntities", 0 );
AddMethod<float, &CEntity::GetDistance>( "getDistance", 1 );
AddMethod<jsval_t, &CEntity::FlattenTerrain>( "flattenTerrain", 0 );
AddClassProperty( L"traits.id.classes", static_cast<GetFn>(&CEntity::GetClassSet), static_cast<SetFn>(&CEntity::SetClassSet) );
AddClassProperty( L"template", static_cast<CEntityTemplate* CEntity::*>(&CEntity::m_base), false, static_cast<NotifyFn>(&CEntity::LoadBase) );
/* Any inherited property MUST be added to EntityTemplate.cpp as well */
AddClassProperty( L"actions.move.speed", &CEntity::m_speed );
AddClassProperty( L"actions.move.run.speed", &CEntity::m_runSpeed );
AddClassProperty( L"actions.move.run.rangeMin", &CEntity::m_runMinRange );
AddClassProperty( L"actions.move.run.range", &CEntity::m_runMaxRange );
AddClassProperty( L"actions.move.run.regenRate", &CEntity::m_runRegenRate );
AddClassProperty( L"actions.move.run.decayRate", &CEntity::m_runDecayRate );
AddClassProperty( L"selected", &CEntity::m_selected, false, static_cast<NotifyFn>(&CEntity::CheckSelection) );
AddClassProperty( L"group", &CEntity::m_grouped, false, static_cast<NotifyFn>(&CEntity::CheckGroup) );
AddClassProperty( L"traits.extant", &CEntity::m_extant );
AddClassProperty( L"actions.move.turningRadius", &CEntity::m_turningRadius );
AddClassProperty( L"position", &CEntity::m_position, false, static_cast<NotifyFn>(&CEntity::Teleport) );
AddClassProperty( L"orientation", &CEntity::m_orientation, false, static_cast<NotifyFn>(&CEntity::Reorient) );
AddClassProperty( L"player", static_cast<GetFn>(&CEntity::JSI_GetPlayer), static_cast<SetFn>(&CEntity::JSI_SetPlayer) );
AddClassProperty( L"traits.health.curr", &CEntity::m_healthCurr );
AddClassProperty( L"traits.health.max", &CEntity::m_healthMax );
AddClassProperty( L"traits.health.regenRate", &CEntity::m_healthRegenRate );
AddClassProperty( L"traits.health.regenStart", &CEntity::m_healthRegenStart );
AddClassProperty( L"traits.health.decayRate", &CEntity::m_healthDecayRate );
AddClassProperty( L"traits.stamina.curr", &CEntity::m_staminaCurr );
AddClassProperty( L"traits.stamina.max", &CEntity::m_staminaMax );
AddClassProperty( L"traits.rank.name", &CEntity::m_rankName );
AddClassProperty( L"traits.vision.los", &CEntity::m_los );
AddClassProperty( L"traits.ai.stance.curr", &CEntity::m_stanceName, false, static_cast<NotifyFn>(&CEntity::StanceChanged) );
AddClassProperty( L"lastCombatTime", &CEntity::m_lastCombatTime );
AddClassProperty( L"lastRunTime", &CEntity::m_lastRunTime );
AddClassProperty( L"building", &CEntity::m_building );
AddClassProperty( L"visible", &CEntity::m_visible );
AddClassProperty( L"productionQueue", &CEntity::m_productionQueue );
AddClassProperty( L"traits.creation.buildingLimitCategory", &CEntity::m_buildingLimitCategory );
CJSComplex<CEntity>::ScriptingInit( "Entity", Construct, 2 );
}
// Script constructor
JSBool CEntity::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
debug_assert( argc >= 2 );
CVector3D position;
float orientation = g_Game->GetSimulation()->RandFloat() * 2 * (float)M_PI;
JSObject* jsEntityTemplate = JSVAL_TO_OBJECT( argv[0] );
CStrW templateName;
CPlayer* player = g_Game->GetPlayer( 0 );
CEntityTemplate* baseEntity = NULL;
if( JSVAL_IS_OBJECT( argv[0] ) ) // only set baseEntity if jsEntityTemplate is a valid object
baseEntity = ToNative<CEntityTemplate>( cx, jsEntityTemplate );
if( !baseEntity )
{
try
{
templateName = g_ScriptingHost.ValueToUCString( argv[0] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
*rval = JSVAL_NULL;
JS_ReportError( cx, "Invalid template identifier" );
return( JS_TRUE );
}
baseEntity = g_EntityTemplateCollection.GetTemplate( templateName );
}
if( !baseEntity )
{
*rval = JSVAL_NULL;
JS_ReportError( cx, "No such template: %s", CStr8(templateName).c_str() );
return( JS_TRUE );
}
JSI_Vector3D::Vector3D_Info* jsVector3D = NULL;
if( JSVAL_IS_OBJECT( argv[1] ) )
jsVector3D = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( argv[1] ), &JSI_Vector3D::JSI_class, NULL );
if( jsVector3D )
{
position = *( jsVector3D->vector );
}
if( argc >= 3 )
{
try
{
orientation = ToPrimitive<float>( argv[2] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
// TODO: Net-safe random for this parameter.
orientation = 0.0f;
}
}
if( argc >= 4 )
{
try
{
player = ToPrimitive<CPlayer*>( argv[3] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
player = g_Game->GetPlayer( 0 );
}
}
std::set<CStr8> selections; // TODO: let scripts specify selections?
HEntity handle = g_EntityManager.Create( baseEntity, position, orientation, selections );
handle->m_actor->SetPlayerID( player->GetPlayerID() );
handle->Initialize();
*rval = ToJSVal<CEntity>( *handle );
return( JS_TRUE );
}
// Script-bound methods
jsval_t CEntity::ToString( JSContext* cx, uintN UNUSED(argc), jsval* UNUSED(argv) )
{
CStrW name( L"[object Entity: " + m_base->m_Tag + L"]" );
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, name.utf16().c_str() ) ) );
}
jsval CEntity::JSI_GetPlayer()
{
return ToJSVal<CPlayer>( m_player );
}
void CEntity::JSI_SetPlayer( jsval val )
{
CPlayer* newPlayer = 0;
try
{
newPlayer = ToPrimitive<CPlayer*>( val );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( g_ScriptingHost.getContext(), "Invalid value given to entity.player - should be a Player object." );
return;
}
// Cancel all production to refund the old player
m_productionQueue->CancelAll();
// Exit all our auras so we can re-enter them as the new player
ExitAuras();
if( m_actor )
m_actor->SetPlayerID( newPlayer->GetPlayerID() ); // calls this->SetPlayer
else
SetPlayer(newPlayer);
}
bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, CEntityOrder::EOrderSource source, bool Queued )
{
// This needs to be sorted (uses Scheduler rather than network messaging)
int orderCode;
debug_assert(argc >= 1);
try
{
orderCode = ToPrimitive<int>( argv[0] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid order type" );
return( false );
}
CEntityOrder newOrder;
newOrder.m_source = source;
CEntity* target;
newOrder.m_type = (CEntityOrder::EOrderType)orderCode;
switch( orderCode )
{
case CEntityOrder::ORDER_GOTO:
case CEntityOrder::ORDER_RUN:
case CEntityOrder::ORDER_PATROL:
JSU_REQUIRE_PARAMS_CPP(3);
try
{
newOrder.m_target_location.x = ToPrimitive<float>( argv[1] );
newOrder.m_target_location.y = ToPrimitive<float>( argv[2] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid location" );
return( false );
}
//It's not a notification order
if ( argc == 3 )
{
if ( entf_get(ENTF_DESTROY_NOTIFIERS) )
{
m_currentRequest=0;
DestroyAllNotifiers();
}
}
break;
case CEntityOrder::ORDER_CONTACT_ACTION:
JSU_REQUIRE_PARAMS_CPP(4);
target = ToNative<CEntity>( argv[1] );
if( !target )
{
JS_ReportError( cx, "Invalid target" );
return( false );
}
newOrder.m_target_entity = target->me;
try
{
newOrder.m_action = ToPrimitive<int>( argv[2] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid generic order type parameter - expected int" );
return( false );
}
try
{
newOrder.m_run = ToPrimitive<bool>( argv[3] );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid generic order run parameter - expected bool" );
return( false );
}
//It's not a notification order
if ( argc == 4 )
{
if ( entf_get(ENTF_DESTROY_NOTIFIERS) )
{
m_currentRequest=0;
DestroyAllNotifiers();
}
}
break;
case CEntityOrder::ORDER_PRODUCE:
JSU_REQUIRE_PARAMS_CPP(3);
try {
newOrder.m_name = ToPrimitive<CStrW>(argv[2]);
newOrder.m_produce_type = ToPrimitive<int>(argv[1]);
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid parameter types" );
return( false );
}
break;
default:
JS_ReportError( cx, "Invalid order type" );
return( false );
}
if( !Queued )
ClearOrders();
PushOrder( newOrder );
return( true );
}
bool CEntity::Kill( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
Kill(true);
return( true );
}
jsval_t CEntity::GetSpawnPoint( JSContext* UNUSED(cx), uintN argc, jsval* argv )
{
float spawn_clearance = 2.0f;
if( argc >= 1 )
{
CEntityTemplate* be = ToNative<CEntityTemplate>( argv[0] );
if( be )
{
switch( be->m_bound_type )
{
case CBoundingObject::BOUND_CIRCLE:
spawn_clearance = be->m_bound_circle->m_radius;
break;
case CBoundingObject::BOUND_OABB:
spawn_clearance = be->m_bound_box->m_radius;
break;
default:
debug_warn(L"No bounding information for spawned object!" );
}
}
else
spawn_clearance = ToPrimitive<float>( argv[0] );
}
else
debug_warn(L"No arguments to Entity::GetSpawnPoint()" );
// TODO: Make netsafe.
CBoundingCircle spawn( 0.0f, 0.0f, spawn_clearance, 0.0f );
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
{
CBoundingBox* oabb = (CBoundingBox*)m_bounds;
// Pick a start point
int edge = g_Game->GetSimulation()->RandInt( 4 );
int point;
double max_w = oabb->m_w + spawn_clearance + 2.0;
double max_d = oabb->m_d + spawn_clearance + 2.0;
int w_count = (int)( max_w * 2 );
int d_count = (int)( max_d * 2 );
CVector2D w_step = oabb->m_v * (float)( max_w / w_count );
CVector2D d_step = oabb->m_u * (float)( max_d / d_count );
CVector2D pos( m_position );
if( edge & 1 )
{
point = g_Game->GetSimulation()->RandInt( 2 * d_count ) - d_count;
pos += ( oabb->m_v * (float)max_w + d_step * (float)point ) * ( ( edge & 2 ) ? -1.0f : 1.0f );
}
else
{
point = g_Game->GetSimulation()->RandInt( 2 * w_count ) - w_count;
pos += ( oabb->m_u * (float)max_d + w_step * (float)point ) * ( ( edge & 2 ) ? -1.0f : 1.0f );
}
int start_edge = edge;
int start_point = point;
spawn.m_pos = pos;
// Then step around the edge (clockwise) until a free space is found, or
// we've gone all the way around.
while( GetCollisionObject( &spawn ) )
{
switch( edge )
{
case 0:
point++;
pos += w_step;
if( point >= w_count )
{
edge = 1;
point = -d_count;
}
break;
case 1:
point++;
pos -= d_step;
if( point >= d_count )
{
edge = 2;
point = w_count;
}
break;
case 2:
point--;
pos -= w_step;
if( point <= -w_count )
{
edge = 3;
point = d_count;
}
break;
case 3:
point--;
pos += d_step;
if( point <= -d_count )
{
edge = 0;
point = -w_count;
}
break;
}
if( ( point == start_point ) && ( edge == start_edge ) )
return( JSVAL_NULL );
spawn.m_pos = pos;
}
CVector3D rval( pos.x, GetAnchorLevel( pos.x, pos.y ), pos.y );
return( ToJSVal( rval ) );
}
else if( m_bounds->m_type == CBoundingObject::BOUND_CIRCLE )
{
float ang;
ang = g_Game->GetSimulation()->RandFloat() * 2 * (float)M_PI;
float radius = m_bounds->m_radius + 1.0f + spawn_clearance;
float d_ang = spawn_clearance / ( 2.0f * radius );
float ang_end = ang + 2.0f * (float)M_PI;
float x = 0.0f, y = 0.0f; // make sure they're initialized
for( ; ang < ang_end; ang += d_ang )
{
x = m_position.X + radius * cos( ang );
y = m_position.Z + radius * sin( ang );
spawn.SetPosition( x, y );
if( !GetCollisionObject( &spawn ) )
break;
}
if( ang < ang_end )
{
// Found a satisfactory position...
CVector3D pos( x, 0, y );
pos.Y = GetAnchorLevel( x, y );
return( ToJSVal( pos ) );
}
else
return( JSVAL_NULL );
}
return( JSVAL_NULL );
}
jsval_t CEntity::AddAura( JSContext* cx, uintN argc, jsval* argv )
{
debug_assert( argc >= 8 );
debug_assert( JSVAL_IS_OBJECT(argv[7]) );
CStrW name = ToPrimitive<CStrW>( argv[0] );
float radius = ToPrimitive<float>( argv[1] );
int tickRate = std::max( 0, ToPrimitive<int>( argv[2] ) ); // since it's a size_t we don't want it to be negative
float r = ToPrimitive<float>( argv[3] );
float g = ToPrimitive<float>( argv[4] );
float b = ToPrimitive<float>( argv[5] );
float a = ToPrimitive<float>( argv[6] );
CVector4D color(r, g, b, a);
JSObject* handler = JSVAL_TO_OBJECT( argv[7] );
if( m_auras[name] )
{
delete m_auras[name];
}
m_auras[name] = new CAura( cx, this, name, radius, tickRate, color, handler );
initAuraData();
return JSVAL_VOID;
}
jsval_t CEntity::RemoveAura( JSContext* UNUSED(cx), uintN argc, jsval* argv )
{
debug_assert( argc >= 1 );
CStrW name = ToPrimitive<CStrW>( argv[0] );
if( m_auras[name] )
{
delete m_auras[name];
m_auras.erase(name);
}
initAuraData();
return JSVAL_VOID;
}
jsval_t CEntity::SetActionParams( JSContext* UNUSED(cx), uintN argc, jsval* argv )
{
debug_assert( argc == 5 );
int id = ToPrimitive<int>( argv[0] );
float minRange = ToPrimitive<int>( argv[1] );
float maxRange = ToPrimitive<int>( argv[2] );
int speed = ToPrimitive<int>( argv[3] );
CStr8 animation = ToPrimitive<CStr8>( argv[4] );
m_actions[id] = SEntityAction( id, minRange, maxRange, speed, animation );
return JSVAL_VOID;
}
bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(4);
CEntityListener notify;
CEntity *target = ToNative<CEntity>( argv[0] );
notify.m_type = (CEntityListener::EType)ToPrimitive<int>( argv[1] );
bool tmpDestroyNotifiers = ToPrimitive<bool>( argv[2] );
entf_set_to(ENTF_DESTROY_NOTIFIERS, !ToPrimitive<bool>( argv[3] ));
if (target == this)
return false;
notify.m_sender = this;
//Clean up old requests
if ( tmpDestroyNotifiers )
DestroyAllNotifiers();
//If new request is not the same and we're destroy notifiers, reset
else if ( !(notify.m_type & m_currentRequest) && entf_get(ENTF_DESTROY_NOTIFIERS))
DestroyAllNotifiers();
m_currentRequest = notify.m_type;
m_notifiers.push_back( target );
int result = target->m_currentNotification & notify.m_type;
//If our target isn't stationary and it's doing something we want to follow, send notification
if ( result && !target->m_orderQueue.empty() )
{
CEntityOrder order = target->m_orderQueue.front();
switch( result )
{
case CEntityListener::NOTIFY_GOTO:
case CEntityListener::NOTIFY_RUN:
DispatchNotification( order, result );
break;
case CEntityListener::NOTIFY_HEAL:
case CEntityListener::NOTIFY_ATTACK:
case CEntityListener::NOTIFY_GATHER:
case CEntityListener::NOTIFY_DAMAGE:
DispatchNotification( order, result );
break;
default:
JS_ReportError( cx, "Invalid order type" );
break;
}
target->m_listeners.push_back( notify );
return true;
}
target->m_listeners.push_back( notify );
return false;
}
int CEntity::GetCurrentRequest( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return m_currentRequest;
}
bool CEntity::ForceCheckListeners( JSContext *cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(2);
int type = ToPrimitive<int>( argv[0] ); //notify code
m_currentNotification = type;
CEntity *target = ToNative<CEntity>( argv[1] );
if ( target->m_orderQueue.empty() )
return false;
CEntityOrder order = target->m_orderQueue.front();
for (size_t i=0; i<m_listeners.size(); i++)
{
int result = m_listeners[i].m_type & type;
if ( result )
{
switch( result )
{
case CEntityListener::NOTIFY_GOTO:
case CEntityListener::NOTIFY_RUN:
case CEntityListener::NOTIFY_HEAL:
case CEntityListener::NOTIFY_ATTACK:
case CEntityListener::NOTIFY_GATHER:
case CEntityListener::NOTIFY_DAMAGE:
case CEntityListener::NOTIFY_IDLE: //target should be 'this'
m_listeners[i].m_sender->DispatchNotification( order, result );
break;
default:
JS_ReportError( cx, "Invalid order type" );
break;
}
}
}
return true;
}
void CEntity::CheckListeners( int type, CEntity *target)
{
m_currentNotification = type;
debug_assert(target);
if ( target->m_orderQueue.empty() )
return;
CEntityOrder order = target->m_orderQueue.front();
for (size_t i=0; i<m_listeners.size(); i++)
{
int result = m_listeners[i].m_type & type;
if ( result )
{
switch( result )
{
case CEntityListener::NOTIFY_GOTO:
case CEntityListener::NOTIFY_RUN:
case CEntityListener::NOTIFY_HEAL:
case CEntityListener::NOTIFY_ATTACK:
case CEntityListener::NOTIFY_GATHER:
case CEntityListener::NOTIFY_DAMAGE:
m_listeners[i].m_sender->DispatchNotification( order, result );
break;
default:
debug_warn(L"Invalid notification: CheckListeners()");
continue;
}
}
}
}
jsval_t CEntity::DestroyAllNotifiers( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
DestroyAllNotifiers();
return JS_TRUE;
}
jsval_t CEntity::DestroyNotifier( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
DestroyNotifier( ToNative<CEntity>( argv[0] ) );
return JS_TRUE;
}
jsval_t CEntity::TriggerRun( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
entf_set(ENTF_TRIGGER_RUN);
return JSVAL_VOID;
}
jsval_t CEntity::SetRun( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
bool should_run = ToPrimitive<bool> ( argv[0] );
entf_set_to(ENTF_SHOULD_RUN, should_run);
entf_set_to(ENTF_IS_RUNNING, should_run);
return JSVAL_VOID;
}
jsval_t CEntity::GetRunState( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return BOOLEAN_TO_JSVAL( entf_get(ENTF_SHOULD_RUN) );
}
jsval_t CEntity::GetFormationPenalty( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetPenalty() );
}
jsval_t CEntity::GetFormationPenaltyBase( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetPenaltyBase() );
}
jsval_t CEntity::GetFormationPenaltyType( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetPenaltyType() );
}
jsval_t CEntity::GetFormationPenaltyVal( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetPenaltyVal() );
}
jsval_t CEntity::GetFormationBonus( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetBonus() );
}
jsval_t CEntity::GetFormationBonusBase( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetBonusBase() );
}
jsval_t CEntity::GetFormationBonusType( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetBonusType() );
}
jsval_t CEntity::GetFormationBonusVal( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( GetFormation()->GetBase()->GetBonusVal() );
}
jsval_t CEntity::RegisterDamage( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
CEntity* inflictor = ToNative<CEntity>( argv[0] );
CVector2D up(1.0f, 0.0f);
CVector2D pos = CVector2D( inflictor->m_position.X, inflictor->m_position.Z );
CVector2D posDelta = (pos - m_position).Normalize();
float angle = acosf( up.Dot(posDelta) );
//Find what section it is between and "activate" it
int sector = FindSector(m_base->m_sectorDivs, angle, DEGTORAD(360.0f))-1;
m_sectorValues[sector]=true;
return JS_TRUE;
}
jsval_t CEntity::RegisterOrderChange( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
CEntity* idleEntity = ToNative<CEntity>( argv[0] );
CVector2D up(1.0f, 0.0f);
CVector2D pos = CVector2D( idleEntity->m_position.X, idleEntity->m_position.Z );
CVector2D posDelta = (pos - m_position).Normalize();
float angle = acosf( up.Dot(posDelta) );
//Find what section it is between and "deactivate" it
int sector = std::max(0, FindSector(m_base->m_sectorDivs, angle, DEGTORAD(360.0f)));
m_sectorValues[sector]=false;
return JS_TRUE;
}
jsval_t CEntity::GetAttackDirections( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
int directions=0;
for ( std::vector<bool>::iterator it=m_sectorValues.begin(); it != m_sectorValues.end(); it++ )
{
if ( *it )
++directions;
}
return ToJSVal( directions );
}
jsval_t CEntity::FindSector( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(4);
try
{
int divs = ToPrimitive<int>( argv[0] );
float angle = ToPrimitive<float>( argv[1] );
float maxAngle = ToPrimitive<float>( argv[2] );
bool negative = ToPrimitive<bool>( argv[3] );
return ToJSVal( FindSector(divs, angle, maxAngle, negative) );
}
catch( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( cx, "Invalid parameters for FindSector" );
return 0;
}
}
jsval_t CEntity::HasRallyPoint( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( entf_get(ENTF_HAS_RALLY_POINT) );
}
jsval_t CEntity::GetRallyPoint( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
CVector3D v3d( m_rallyPoint.x, m_rallyPoint.y, 0 );
return ToJSVal( v3d );
}
jsval_t CEntity::SetRallyPointAtCursor( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
// Queue an order over the network to set a rally point
/*
CSetRallyPointMessage* msg = new CSetRallyPointMessage;
msg->m_Entities = CEntityList(me);
msg->m_IsQueued = true;
CVector3D point = g_Game->GetView()->GetCamera()->GetWorldCoordinates(true);
msg->m_TargetX = (int) point.X;
msg->m_TargetY = (int) point.Z;
g_Game->GetSimulation()->QueueLocalCommand(msg);
*/
return JS_TRUE;
}
// Called by the script when the entity is damaged, to let it retaliate
jsval_t CEntity::OnDamaged( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
CEntity* damageSource = ToNative<CEntity>( argv[0] );
m_stance->OnDamaged( damageSource );
return JSVAL_VOID;
}
jsval_t CEntity::GetVisibleEntities( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
std::vector<CEntity*> pointers;
g_EntityManager.GetInLOS( this, pointers );
std::vector<HEntity> handles( pointers.size() );
for( size_t i=0; i<pointers.size(); i++ )
handles[i] = pointers[i]->me;
return OBJECT_TO_JSVAL( EntityCollection::Create( handles ) );
}
float CEntity::GetDistance( JSContext* cx, uintN argc, jsval* argv )
{
JSU_REQUIRE_PARAMS_CPP(1);
CEntity* target = ToNative<CEntity>( argv[0] );
if( !target )
return -1.0f;
return this->Distance2D( target );
}
/*
Methods that provide an interface from C++ to JavaScript functions.
*/
int CEntity::GetAttackAction( HEntity target )
{
jsval attackFunc;
if( GetProperty( g_ScriptingHost.GetContext(), L"getAttackAction", &attackFunc ) )
{
jsval arg = ToJSVal( target );
jsval rval;
if( JS_CallFunctionValue( g_ScriptingHost.GetContext(), GetScript(), attackFunc, 1, &arg, &rval ) == JS_TRUE )
{
return ToPrimitive<int>( rval );
}
}
// Default return value is an invalid action ID
return 0;
}
jsval_t CEntity::FlattenTerrain( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
float xDiff, yDiff;
CVector3D pos = m_position;
CVector2D pos2D(m_position.X, m_position.Z);
if ( m_bounds->m_type == CBoundingObject::BOUND_CIRCLE )
xDiff = yDiff = m_bounds->m_radius;
else
{
CBoundingBox* box = static_cast<CBoundingBox*>( m_bounds );
xDiff = box->m_w;
yDiff = box->m_d;
}
//If we ever need to take rotated bounding boxes into account...
//CVector2D points[4] = { CVector2D(xDiff, yDiff), CVector2D(-xDiff, -yDiff),
//CVector2D(-xDiff, yDiff), CVector2D(xDiff, yDiff) };
//CVector3D circle = points[0].FindCircumCircle(points[1], points[2]);
//float cos = cosf(m_graphics_orientation.Y), sin = sinf(m_graphics_orientation.Y);
//for ( size_t i = 0; i<4; ++i )
//{
// points[i].x *= cos*circle.Z;
// points[i].y *= sin*circle.Z;
//}
g_Game->GetWorld()->GetTerrain()->FlattenArea(pos.X-xDiff, pos.X+xDiff, pos.Z-yDiff, pos.Z+yDiff);
SnapToGround();
return JS_TRUE;
}

View File

@ -30,7 +30,6 @@
#include "ProductionQueue.h"
#include "maths/MathUtil.h"
#include "Collision.h"
#include "PathfindEngine.h"
#include "LOSManager.h"
#include "graphics/Terrain.h"
#include "Stance.h"
@ -478,7 +477,7 @@ bool CEntity::ProcessContactAction( CEntityOrder* current,
// The pathfinder will push its result back into this unit's queue and
// add back the current order at the end with the transition type.
current->m_type = transition;
g_Pathfinder.RequestContactPath( me, current, action->m_MaxRange );
// g_Pathfinder.RequestContactPath( me, current, action->m_MaxRange );
return true;
}
@ -579,11 +578,11 @@ bool CEntity::ProcessContactActionNoPathing( CEntityOrder* current, int timestep
ChooseMovementSpeed( action->m_MinRange );
// The pathfinder will push its result in front of the current order
if( !g_Pathfinder.RequestAvoidPath( me, current, action->m_MinRange + 2.0f ) )
{
m_actor->SetAnimationState( "idle", false, 1.f, 0.f, false, L"" ); // Nothing we can do.. maybe we'll find a better target
PopOrder();
}
// if( !g_Pathfinder.RequestAvoidPath( me, current, action->m_MinRange + 2.0f ) )
// {
// m_actor->SetAnimationState( "idle", false, 1.f, 0.f, false, L"" ); // Nothing we can do.. maybe we'll find a better target
// PopOrder();
// }
return false;
}
@ -694,7 +693,7 @@ bool CEntity::ProcessGoto( CEntityOrder* current, int UNUSED(timestep_millis) )
// The pathfinder will push its result back into this unit's queue.
g_Pathfinder.RequestPath( me, path_to, source );
// g_Pathfinder.RequestPath( me, path_to, source );
return( true );
}
@ -729,7 +728,7 @@ bool CEntity::ProcessGotoWaypoint( CEntityOrder* current, int UNUSED(timestep_mi
else
#endif // USE_DCDT
{
g_Pathfinder.RequestLowLevelPath( me, path_to, contact, pathfinder_radius, source );
// g_Pathfinder.RequestLowLevelPath( me, path_to, contact, pathfinder_radius, source );
}

View File

@ -1,140 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EntitySupport.h"
bool CClassSet::IsMember( const CStrW& Test )
{
for(size_t i = 0; i < m_Members.size(); i++)
{
if(m_Members[i] == Test)
{
// Move to Front algo (currently disabled)
//std::swap(m_Members[0], m_Members[i]);
return true;
}
}
return false;
}
void CClassSet::Rebuild()
{
if( m_Parent )
m_Members = m_Parent->m_Members;
else
m_Members.clear();
Set newMembers;
for( size_t i=0; i<m_Members.size(); ++i )
{
const CStrW& member = m_Members[i];
for(size_t j=0; j<m_RemovedMembers.size(); j++)
{
if(m_RemovedMembers[j] == member)
goto end;
}
for(size_t j=0; j<m_AddedMembers.size(); j++)
{
if(m_AddedMembers[j] == member)
goto end;
}
newMembers.push_back(member);
end:;
}
for(size_t j=0; j<m_AddedMembers.size(); j++)
{
newMembers.push_back(m_AddedMembers[j]);
}
m_Members = newMembers;
}
CStrW CClassSet::GetMemberList()
{
Set::iterator it = m_Members.begin();
CStrW result = L"";
if( it != m_Members.end() )
{
result = *( it++ );
for( ; it != m_Members.end(); ++it )
result += L" " + *it;
}
return result;
}
void CClassSet::SetFromMemberList(const CStrW& list)
{
CStr entry;
CStr temp = list;
m_AddedMembers.clear();
m_RemovedMembers.clear();
while( true )
{
// Find the first ' ' or ',' in the string
int brk = temp.Find(' ');
int comma = temp.Find(',');
if( comma != -1 && ( brk == -1 || comma < brk ) )
{
brk = comma;
}
if( brk == -1 )
{
entry = temp;
}
else
{
entry = temp.substr( 0, brk );
temp = temp.substr( brk + 1 );
}
if( brk != 0 )
{
if( entry[0] == '-' )
{
entry = entry.substr( 1 );
if( ! entry.empty() )
m_RemovedMembers.push_back( entry );
}
else
{
if( entry[0] == '+' )
entry = entry.substr( 1 );
if( ! entry.empty() )
m_AddedMembers.push_back( entry );
}
}
if( brk == -1 )
{
break;
}
}
}

View File

@ -1,60 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// Supporting data types for CEntity and related
#ifndef INCLUDED_ENTITYSUPPORT
#define INCLUDED_ENTITYSUPPORT
#include "ps/CStr.h"
struct SEntityAction
{
int m_Id;
float m_MinRange;
float m_MaxRange;
int m_Speed;
CStr8 m_Animation;
SEntityAction()
: m_Id(0), m_MinRange(0), m_MaxRange(0), m_Speed(1000), m_Animation("walk") {}
SEntityAction(int id, float minRange, float maxRange, int speed, CStr8& animation)
: m_Id(id), m_MinRange(minRange), m_MaxRange(maxRange), m_Speed(speed), m_Animation(animation) {}
};
class CClassSet
{
CClassSet* m_Parent;
typedef std::vector<CStrW> Set;
Set m_Members;
Set m_AddedMembers; // Members that this set adds to on top of those in its parent
Set m_RemovedMembers; // Members that this set removes even if its parent has them
public:
CClassSet() : m_Parent(NULL) {}
bool IsMember(const CStrW& Test);
void Rebuild();
inline void SetParent(CClassSet* Parent)
{ m_Parent = Parent; Rebuild(); }
CStrW GetMemberList();
void SetFromMemberList(const CStrW& list);
};
#endif

View File

@ -1,511 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EntityTemplate.h"
#include "EntityTemplateCollection.h"
#include "graphics/ObjectManager.h"
#include "ps/CStr.h"
#include "ps/Player.h"
#include "scripting/ScriptableComplex.inl"
#include "ps/XML/Xeromyces.h"
//#include "sound/SoundGroupMgr.h"
#include "ps/CLogger.h"
#define LOG_CATEGORY L"entity"
STL_HASH_SET<CStr, CStr_hash_compare> CEntityTemplate::scriptsLoaded;
// Utility functions used in reading XML
namespace {
/**
* Converts the given string, consisting of underscores and letters,
* to camelCase: the first letter of each underscore-separated "word"
* is changed to lowercase. For example, the string MiniMap_Colour
* is converted to miniMap_colour.
*
* @param const std::string & str The string to convert.
* @return std::string The given string in camelCase.
**/
std::string toCamelCase( const std::string& str )
{
std::string ret = str;
for( size_t i=0; i<ret.size(); i++ )
{
if( i==0 || ret[i-1] == '_' )
{
ret[i] = tolower( ret[i] );
}
}
return ret;
}
}
CEntityTemplate::CEntityTemplate( CPlayer* player )
{
m_player = player;
m_base = NULL;
AddProperty( L"tag", &m_Tag, false );
AddProperty( L"parent", &m_base, false );
AddProperty( L"unmodified", &m_unmodified, false );
for( int t = 0; t < EVENT_LAST; t++ )
{
AddProperty( EventNames[t], &m_EventHandlers[t], false );
AddHandler( t, &m_EventHandlers[t] );
}
// Initialize, make life a little easier on the scriptors
m_speed = m_turningRadius = 0.0f;
//m_extant = true;
m_foundation = CStrW();
m_socket = CStrW();
m_passThroughAllies = false;
m_sectorDivs = 4;
// Sentinel values for stamina and health (so scripts can check if an entity has no stamina or no HP).
m_speed = 0;
m_staminaMax = 0;
m_healthMax = 0;
m_bound_type = CBoundingObject::BOUND_NONE;
m_bound_circle = NULL;
m_bound_box = NULL;
// If these aren't set, we can get an infinite loop in CEntity::interpolate, which is nasty; they
// should be set in template_entity, but do this in case some entity forgets to inherit from that
m_anchorConformX = 0;
m_anchorConformZ = 0;
}
CEntityTemplate::~CEntityTemplate()
{
if( m_bound_box )
delete( m_bound_box );
if( m_bound_circle )
delete( m_bound_circle );
}
void CEntityTemplate::LoadBase()
{
// Copy the parent's bounds, unless we're providing a replacement.
if( m_bound_type == CBoundingObject::BOUND_NONE )
{
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
{
m_bound_circle = new CBoundingCircle();
m_bound_circle->SetRadius( m_base->m_bound_circle->m_radius );
m_bound_circle->SetHeight( m_base->m_bound_circle->m_height );
}
else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
{
m_bound_box = new CBoundingBox();
m_bound_box->SetDimensions( m_base->m_bound_box->GetWidth(), m_base->m_bound_box->GetDepth() );
m_bound_box->SetHeight( m_base->m_bound_box->m_height );
}
m_bound_type = m_base->m_bound_type;
}
// Initialize sound group table from the parent's sound group table
for(SoundGroupTable::iterator it = m_base->m_SoundGroupTable.begin();
it != m_base->m_SoundGroupTable.end(); ++it)
{
m_SoundGroupTable[it->first] = it->second;
}
SetBase( m_base );
m_classes.SetParent( &( m_base->m_classes ) );
SetNextObject( m_base );
}
jsval CEntityTemplate::GetClassSet()
{
CStrW result = m_classes.GetMemberList();
return( ToJSVal( result ) );
}
void CEntityTemplate::SetClassSet( jsval value )
{
CStr memberCmdList = ToPrimitive<CStrW>( value );
m_classes.SetFromMemberList(memberCmdList);
RebuildClassSet();
}
void CEntityTemplate::RebuildClassSet()
{
m_classes.Rebuild();
InheritorsList::iterator it;
for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ )
(*it)->RebuildClassSet();
}
bool CEntityTemplate::LoadXml( const VfsPath& pathname )
{
CXeromyces XeroFile;
if (XeroFile.Load(pathname) != PSRETURN_OK)
// Fail
return false;
// Define all the elements and attributes used in the XML file
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
// Only the ones we can't load using normal methods.
EL(Entity);
EL(Script);
EL(Event);
EL(Traits);
EL(Footprint);
EL(Depth);
EL(Height);
EL(Radius);
EL(Width);
EL(SoundGroups);
AT(Parent);
AT(On);
AT(File);
AT(Function);
#undef AT
#undef EL
XMBElement Root = XeroFile.GetRoot();
if( Root.GetNodeName() != el_Entity )
{
LOG(CLogger::Error, LOG_CATEGORY, L"CEntityTemplate::LoadXml: XML root was not \"Entity\" in file %ls. Load failed.", pathname.string().c_str() );
return( false );
}
XMBElementList RootChildren = Root.GetChildNodes();
m_Tag = CStr(pathname.string()).AfterLast("/").BeforeLast(".xml");
m_Base_Name = Root.GetAttributes().GetNamedItem( at_Parent );
// Load our parent, if we have one
if( ! m_Base_Name.empty() )
{
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate( m_Base_Name, m_player );
if( base )
{
m_base = base;
LoadBase();
}
else
{
LOG(CLogger::Warning, LOG_CATEGORY, L"Parent template \"%ls\" does not exist in template \"%ls\"", m_Base_Name.c_str(), m_Tag.c_str() );
// (The requested entity will still be returned, but with no parent.
// Is this a reasonable thing to do?)
}
}
for (int i = 0; i < RootChildren.Count; ++i)
{
XMBElement Child = RootChildren.Item(i);
int ChildName = Child.GetNodeName();
if( ChildName == el_Script )
{
CStr Include = Child.GetAttributes().GetNamedItem( at_File );
if( !Include.empty() && scriptsLoaded.find( Include ) == scriptsLoaded.end() )
{
scriptsLoaded.insert( Include );
g_ScriptingHost.RunScript( CStrW(Include) );
}
CStr Inline = Child.GetText();
if( !Inline.empty() )
{
CStr pathname_c = CStr(pathname.string());
g_ScriptingHost.RunMemScript( Inline.c_str(), Inline.length(), pathname_c.c_str(), Child.GetLineNumber() );
}
}
else if (ChildName == el_Traits)
{
XMBElementList TraitChildren = Child.GetChildNodes();
for(int j = 0; j < TraitChildren.Count; ++j)
{
XMBElement TraitChild = TraitChildren.Item(j);
int TraitChildName = TraitChild.GetNodeName();
if( TraitChildName == el_Footprint )
{
XMBElementList FootprintChildren = TraitChild.GetChildNodes();
float radius=0, height=0, width=0, depth=0;
bool hadRadius = false, hadDepth = false;
for(int k = 0; k < FootprintChildren.Count; ++k)
{
XMBElement FootprintChild = FootprintChildren.Item(k);
int FootprintChildName = FootprintChild.GetNodeName();
if( FootprintChildName == el_Radius )
{
hadRadius = true;
radius = CStrW( FootprintChild.GetText() ).ToFloat();
}
else if( FootprintChildName == el_Width )
{
width = CStrW( FootprintChild.GetText() ).ToFloat();
}
else if( FootprintChildName == el_Height )
{
height = CStrW( FootprintChild.GetText() ).ToFloat();
}
else if( FootprintChildName == el_Depth )
{
hadDepth = true;
depth = CStrW( FootprintChild.GetText() ).ToFloat();
}
}
if( hadRadius )
{
// Specifying a circular footprint
if( !m_bound_circle )
m_bound_circle = new CBoundingCircle();
m_bound_circle->SetRadius( radius );
m_bound_circle->SetHeight( height );
m_bound_type = CBoundingObject::BOUND_CIRCLE;
}
else if( hadDepth )
{
// Specifying a rectangular footprint
if( !m_bound_box )
m_bound_box = new CBoundingBox();
m_bound_box->SetDimensions( width, depth );
m_bound_box->SetHeight( height );
m_bound_type = CBoundingObject::BOUND_OABB;
}
// Else, entity has no footprint.
}
}
// important so that scripts can see traits
XMLLoadProperty( XeroFile, Child, CStrW() );
}
else if( ChildName == el_Event )
{
// Action...On for consistency with the GUI.
CStrW EventName = L"on" + (CStrW)Child.GetAttributes().GetNamedItem( at_On );
CStrW Code (Child.GetText());
utf16string ExternalFunction = Child.GetAttributes().GetNamedItem( at_Function );
// Does a property with this name already exist?
for( size_t eventID = 0; eventID < EVENT_LAST; eventID++ )
{
if( CStrW( EventNames[eventID] ) == EventName )
{
if( ExternalFunction != utf16string() )
{
jsval fnval;
JSBool ret = JS_GetUCProperty( g_ScriptingHost.GetContext(), g_ScriptingHost.GetGlobalObject(), ExternalFunction.c_str(), ExternalFunction.size(), &fnval );
debug_assert( ret );
JSFunction* fn = JS_ValueToFunction( g_ScriptingHost.GetContext(), fnval );
if( !fn )
{
LOG(CLogger::Error, LOG_CATEGORY, L"CEntityTemplate::LoadXml: Function does not exist for event %ls in file %ls. Load failed.", EventName.c_str(), pathname.string().c_str() );
break;
}
m_EventHandlers[eventID].SetFunction( fn );
}
else
m_EventHandlers[eventID].Compile( pathname.string() + L"::" + EventName + L" (" + CStrW( Child.GetLineNumber() ) + L")", Code );
HasProperty( EventName )->m_Inherited = false;
break;
}
}
}
else if( ChildName == el_SoundGroups )
{
#if 0
// Read every child element's value into m_SoundGroupTable with its tag as the key
XMBElementList children = Child.GetChildNodes();
for(int j = 0; j < children.Count; ++j)
{
XMBElement child = children.Item(j);
CStr8 name = toCamelCase( XeroFile.GetElementString( child.GetNodeName() ) );
VfsPath soundGroupFilename = CStrW(child.GetText());
const size_t soundGroupIndex = g_soundGroupMgr->AddGroup(soundGroupFilename);
m_SoundGroupTable[name] = soundGroupIndex;
}
#endif
}
else
{
XMLLoadProperty( XeroFile, Child, CStrW() );
}
}
if( m_player == 0 )
{
m_unmodified = this;
}
else
{
m_unmodified = g_EntityTemplateCollection.GetTemplate( m_Tag, 0 );
}
return true;
}
void CEntityTemplate::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& Source, const CStrW& BasePropertyName )
{
// Add a property, put the node text into it.
CStrW PropertyName = BasePropertyName + CStrW( toCamelCase( XeroFile.GetElementString( Source.GetNodeName() ) ) );
IJSComplexProperty* Existing = HasProperty( PropertyName );
if( Existing )
{
if( !Existing->m_Intrinsic )
LOG(CLogger::Warning, LOG_CATEGORY, L"CEntityTemplate::XMLAddProperty: %ls already defined for %ls. Property trees will be merged.", PropertyName.c_str(), m_Tag.c_str() );
Existing->Set( this, JSParseString( Source.GetText() ) );
//Existing->m_Inherited = false;
}
else
{
if( !Source.GetText().length() )
{
// Arbitrarily say that if a node has no other value, define it to be 'true'.
// Appears to be the most convenient thing to do in most circumstances.
AddProperty( PropertyName, JSVAL_TRUE );
}
else
{
AddProperty( PropertyName, Source.GetText() );
}
}
PropertyName += L".";
// Retrieve any attributes it has and add them as subproperties.
XMBAttributeList AttributeSet = Source.GetAttributes();
for( int AttributeID = 0; AttributeID < AttributeSet.Count; AttributeID++ )
{
XMBAttribute Attribute = AttributeSet.Item( AttributeID );
CStrW AttributeName = PropertyName + CStr8( toCamelCase( XeroFile.GetAttributeString( Attribute.Name ) ) );
Existing = HasProperty( AttributeName );
if( Existing )
{
Existing->Set( this, JSParseString( Attribute.Value ) );
Existing->m_Inherited = false;
}
else
AddProperty( AttributeName, Attribute.Value );
}
// Retrieve any child nodes the property has and, similarly, add them as subproperties.
XMBElementList NodeSet = Source.GetChildNodes();
for( int NodeID = 0; NodeID < NodeSet.Count; NodeID++ )
{
XMBElement Node = NodeSet.Item( NodeID );
XMLLoadProperty( XeroFile, Node, PropertyName );
}
}
/*
Scripting Interface
*/
// Scripting initialization
void CEntityTemplate::ScriptingInit()
{
AddMethod<CStr, &CEntityTemplate::ToString>( "toString", 0 );
AddClassProperty( L"traits.id.classes", static_cast<GetFn>(&CEntityTemplate::GetClassSet), static_cast<SetFn>(&CEntityTemplate::SetClassSet) );
AddClassProperty( L"actions.move.speed", &CEntityTemplate::m_speed );
AddClassProperty( L"actions.move.turningRadius", &CEntityTemplate::m_turningRadius );
AddClassProperty( L"actions.move.run.speed", &CEntityTemplate::m_runSpeed );
AddClassProperty( L"actions.move.run.rangeMin", &CEntityTemplate::m_runMinRange );
AddClassProperty( L"actions.move.run.range", &CEntityTemplate::m_runMaxRange );
AddClassProperty( L"actions.move.run.regenRate", &CEntityTemplate::m_runRegenRate );
AddClassProperty( L"actions.move.run.decayRate", &CEntityTemplate::m_runDecayRate );
AddClassProperty( L"actions.move.passThroughAllies", &CEntityTemplate::m_passThroughAllies );
AddClassProperty( L"actor", &CEntityTemplate::m_actorName );
AddClassProperty( L"traits.health.max", &CEntityTemplate::m_healthMax );
AddClassProperty( L"traits.health.barHeight", &CEntityTemplate::m_healthBarHeight );
AddClassProperty( L"traits.health.barSize", &CEntityTemplate::m_healthBarSize );
AddClassProperty( L"traits.health.barWidth", &CEntityTemplate::m_healthBarWidth );
AddClassProperty( L"traits.health.borderHeight", &CEntityTemplate::m_healthBorderHeight);
AddClassProperty( L"traits.health.borderWidth", &CEntityTemplate::m_healthBorderWidth );
AddClassProperty( L"traits.health.borderName", &CEntityTemplate::m_healthBorderName );
AddClassProperty( L"traits.health.regenRate", &CEntityTemplate::m_healthRegenRate );
AddClassProperty( L"traits.health.regenStart", &CEntityTemplate::m_healthRegenStart );
AddClassProperty( L"traits.health.decayRate", &CEntityTemplate::m_healthDecayRate );
AddClassProperty( L"traits.stamina.max", &CEntityTemplate::m_staminaMax );
AddClassProperty( L"traits.stamina.barHeight", &CEntityTemplate::m_staminaBarHeight );
AddClassProperty( L"traits.stamina.barSize", &CEntityTemplate::m_staminaBarSize );
AddClassProperty( L"traits.stamina.barWidth", &CEntityTemplate::m_staminaBarWidth );
AddClassProperty( L"traits.stamina.borderHeight", &CEntityTemplate::m_staminaBorderHeight);
AddClassProperty( L"traits.stamina.borderWidth", &CEntityTemplate::m_staminaBorderWidth );
AddClassProperty( L"traits.stamina.borderName", &CEntityTemplate::m_staminaBorderName );
AddClassProperty( L"traits.rally.name", &CEntityTemplate::m_rallyName );
AddClassProperty( L"traits.rally.width", &CEntityTemplate::m_rallyWidth );
AddClassProperty( L"traits.rally.height", &CEntityTemplate::m_rallyHeight );
AddClassProperty( L"traits.flankPenalty.sectors", &CEntityTemplate::m_sectorDivs );
AddClassProperty( L"traits.pitch.sectors", &CEntityTemplate::m_pitchDivs );
AddClassProperty( L"traits.pitch.value", &CEntityTemplate::m_pitchValue );
AddClassProperty( L"traits.rank.width", &CEntityTemplate::m_rankWidth );
AddClassProperty( L"traits.rank.height", &CEntityTemplate::m_rankHeight );
AddClassProperty( L"traits.rank.name", &CEntityTemplate::m_rankName );
AddClassProperty( L"traits.ai.stance.curr", &CEntityTemplate::m_stanceName );
AddClassProperty( L"traits.miniMap.type", &CEntityTemplate::m_minimapType );
AddClassProperty( L"traits.miniMap.red", &CEntityTemplate::m_minimapR );
AddClassProperty( L"traits.miniMap.green", &CEntityTemplate::m_minimapG );
AddClassProperty( L"traits.miniMap.blue", &CEntityTemplate::m_minimapB );
AddClassProperty( L"traits.anchor.type", &CEntityTemplate::m_anchorType );
AddClassProperty( L"traits.anchor.conformX", &CEntityTemplate::m_anchorConformX );
AddClassProperty( L"traits.anchor.conformZ", &CEntityTemplate::m_anchorConformZ );
AddClassProperty( L"traits.vision.los", &CEntityTemplate::m_los );
AddClassProperty( L"traits.vision.permanent", &CEntityTemplate::m_visionPermanent );
AddClassProperty( L"traits.display.bars.enabled", &CEntityTemplate::m_barsEnabled );
AddClassProperty( L"traits.display.bars.offset", &CEntityTemplate::m_barOffset );
AddClassProperty( L"traits.display.bars.height", &CEntityTemplate::m_barHeight );
AddClassProperty( L"traits.display.bars.width", &CEntityTemplate::m_barWidth );
AddClassProperty( L"traits.display.bars.border", &CEntityTemplate::m_barBorder );
AddClassProperty( L"traits.display.bars.borderSize", &CEntityTemplate::m_barBorderSize );
AddClassProperty( L"traits.isTerritoryCentre", &CEntityTemplate::m_isTerritoryCentre );
AddClassProperty( L"traits.creation.foundation", &CEntityTemplate::m_foundation );
AddClassProperty( L"traits.creation.socket", &CEntityTemplate::m_socket );
AddClassProperty( L"traits.creation.territoryRestriction", &CEntityTemplate::m_territoryRestriction );
AddClassProperty( L"traits.creation.buildingLimitCategory", &CEntityTemplate::m_buildingLimitCategory );
CJSComplex<CEntityTemplate>::ScriptingInit( "EntityTemplate" );
}
// Script-bound functions
JSObject* CEntityTemplate::GetScriptExecContext( IEventTarget* target )
{
return( target->GetScriptExecContext( target ) );
}
CStr CEntityTemplate::ToString( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
if( m_player == 0 )
return "[object EntityTemplate: " + CStr(m_Tag) + " base]";
else
return "[object EntityTemplate: " + CStr(m_Tag) + " for player " + CStr((unsigned)m_player->GetPlayerID()) + "]";
}

View File

@ -1,198 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// EntityTemplate.h
//
// Entity Templates
//
// Usage: These templates are used as the default values for entity properties.
// Due to Pyrogenesis' data-inheritance model for these properties,
// templates specify a base-template, then override only those properties
// in that template that need to change.
// Similarly, entities need only specify properties they possess that are
// different to the ones in their respective templates. Of course,
// properties such as position, current HP, etc. cannot be inherited from
// a template in this way.
//
#ifndef INCLUDED_ENTITYTEMPLATE
#define INCLUDED_ENTITYTEMPLATE
#include "ps/CStr.h"
#include "lib/file/vfs/vfs_path.h"
#include "scripting/ScriptableComplex.h"
#include "scripting/DOMEvent.h"
#include "BoundingObjects.h"
#include "EntitySupport.h"
#include "ScriptObject.h"
class CPlayer;
class CXeromyces;
class XMBElement;
class CEntityTemplate : public CJSComplex<CEntityTemplate>, public IEventTarget
{
NONCOPYABLE(CEntityTemplate);
public:
CPlayer* m_player; // Which player this template is for, or null for the no-player template
// used to read unmodified values for upgrades and such.
CEntityTemplate(CPlayer* player);
~CEntityTemplate();
// Load from XML
bool LoadXml(const VfsPath& filename);
// Load a tree of properties from an XML (XMB) node.
void XMLLoadProperty(const CXeromyces& XeroFile, const XMBElement& Source, const CStrW& BasePropertyName);
// Base stats
CEntityTemplate* m_base;
//bool m_extant;
// The unmodified, no-player version of this template
CEntityTemplate* m_unmodified;
// The class types this entity has
CClassSet m_classes;
CStrW m_Base_Name; // <- We don't guarantee the order XML files will be loaded in, so we'll store the name of the
// parent entity referenced, then, after all files are loaded, attempt to match names to objects.
CStrW m_actorName;
CStrW m_Tag;
CBoundingCircle* m_bound_circle;
CBoundingBox* m_bound_box;
CBoundingObject::EBoundingType m_bound_type;
// Sound properties
// map animation name to soundGroup index returned by SoundGroupMgr
typedef STL_HASH_MAP<CStr, size_t, CStr_hash_compare> SoundGroupTable;
SoundGroupTable m_SoundGroupTable;
//SP properties
float m_staminaMax;
// HP properties
float m_healthMax;
float m_healthRegenRate;
float m_healthRegenStart;
float m_healthDecayRate;
// Display properties
bool m_barsEnabled;
float m_barOffset;
float m_barHeight;
float m_barWidth;
float m_barBorderSize;
CStr m_barBorder;
float m_staminaBarHeight;
int m_staminaBarSize;
float m_staminaBarWidth;
int m_staminaBorderWidth;
int m_staminaBorderHeight;
CStr m_staminaBorderName;
float m_healthBarHeight;
int m_healthBarSize;
float m_healthBarWidth;
int m_healthBorderWidth;
int m_healthBorderHeight;
CStr m_healthBorderName;
float m_rankWidth;
float m_rankHeight;
// Stance name
CStr m_stanceName;
//Rank properties
CStr m_rankName;
//Rally name
CStr m_rallyName;
float m_rallyWidth;
float m_rallyHeight;
// Minimap properties
CStrW m_minimapType;
int m_minimapR;
int m_minimapG;
int m_minimapB;
// Y anchor
CStrW m_anchorType;
// LOS
int m_los;
bool m_visionPermanent;
// Is this object a territory centre? (e.g. Settlements in 0AD)
bool m_isTerritoryCentre;
// Foundation entity, or "" for none
CStrW m_foundation;
// Socket entity that we can be built on, or "" for free placement
CStrW m_socket;
// Can be "allied" to allow placement only in allied territories, or "" or "all" for all territories
CStrW m_territoryRestriction;
// Territorial limit
CStrW m_buildingLimitCategory;
float m_speed;
float m_runSpeed;
float m_runRegenRate;
float m_runDecayRate;
bool m_passThroughAllies;
float m_runMaxRange;
float m_runMinRange;
int m_sectorDivs;
int m_pitchDivs;
float m_pitchValue;
float m_anchorConformX;
float m_anchorConformZ;
float m_turningRadius;
CScriptObject m_EventHandlers[EVENT_LAST];
void LoadBase();
jsval GetClassSet();
void SetClassSet( jsval value );
void RebuildClassSet();
// Script-bound functions
// Get script execution contexts - always run in the context of the entity that fired it.
JSObject* GetScriptExecContext(IEventTarget* target);
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
static void ScriptingInit();
private:
static STL_HASH_SET<CStr, CStr_hash_compare> scriptsLoaded;
};
#endif

View File

@ -1,126 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EntityTemplateCollection.h"
#include "EntityTemplate.h"
#include "graphics/ObjectManager.h"
#include "graphics/Model.h"
#include "ps/CLogger.h"
#include "ps/Player.h"
#include "ps/Game.h"
#define LOG_CATEGORY L"entity"
#include <boost/filesystem.hpp>
void CEntityTemplateCollection::LoadFile( const VfsPath& pathname )
{
// Build the entity name -> filename mapping. This is done so that
// the entity 'x' can be in units/x.xml, structures/x.xml, etc, and
// we don't have to search every directory for x.xml.
const CStrW basename(fs::basename(pathname));
m_templateFilenames[basename] = pathname;
}
static LibError LoadFileThunk( const VfsPath& path, const FileInfo& UNUSED(fileInfo), uintptr_t cbData )
{
CEntityTemplateCollection* this_ = (CEntityTemplateCollection*)cbData;
this_->LoadFile(path);
return INFO::CB_CONTINUE;
}
int CEntityTemplateCollection::LoadTemplates()
{
// List all files in entities/ and its subdirectories.
THROW_ERR( fs_util::ForEachFile(g_VFS, L"entities/", LoadFileThunk, (uintptr_t)this, L"*.xml", fs_util::DIR_RECURSIVE));
/*// Load all the templates; this is necessary so that we can apply techs to them
// (otherwise a tech can't affect the template of a unit that doesn't yet exist)
for( TemplateFilenameMap::iterator it = m_templateFilenames.begin(); it != m_templateFilenames.end(); ++it )
{
// Load the no-player version of this template (used by techs for base values)
GetTemplate( it->first, 0 );
for( size_t i=0; i<=g_Game->GetNumPlayers(); i++ )
{
// TODO: Load the template just once and clone it to get these player templates
GetTemplate( it->first, g_Game->GetPlayer(i) );
}
}*/
return 0;
}
CEntityTemplate* CEntityTemplateCollection::GetTemplate( const CStrW& name, CPlayer* player )
{
// Find player ID
size_t id = ( player == 0 ? NULL_PLAYER : player->GetPlayerID() );
// Check whether this template has already been loaded
TemplateMap::iterator it = m_templates[id].find( name );
if( it != m_templates[id].end() )
return( it->second );
// Find the filename corresponding to this template
TemplateFilenameMap::iterator filename_it = m_templateFilenames.find( name );
if( filename_it == m_templateFilenames.end() )
return( NULL );
VfsPath path( filename_it->second );
// Try to load to the entity
CEntityTemplate* newTemplate = new CEntityTemplate( player );
if( !newTemplate->LoadXml( path ) )
{
LOG(CLogger::Error, LOG_CATEGORY, L"CEntityTemplateCollection::GetTemplate(): Couldn't load template \"%ls\"", path.string().c_str());
delete newTemplate;
return( NULL );
}
LOG(CLogger::Normal, LOG_CATEGORY, L"CEntityTemplateCollection::GetTemplate(): Loaded template \"%ls\"", path.string().c_str());
m_templates[id][name] = newTemplate;
return newTemplate;
}
void CEntityTemplateCollection::GetEntityTemplateNames( std::vector<CStrW>& names )
{
for( TemplateFilenameMap::iterator it = m_templateFilenames.begin(); it != m_templateFilenames.end(); ++it )
if( ! (it->first.length() > 8 && it->first.Left(8) == L"template"))
names.push_back( it->first );
}
void CEntityTemplateCollection::GetPlayerTemplates( CPlayer* player, std::vector<CEntityTemplate*>& dest )
{
size_t id = ( player == 0 ? NULL_PLAYER : player->GetPlayerID() );
for( TemplateMap::iterator it = m_templates[id].begin(); it != m_templates[id].end(); ++it )
{
dest.push_back( it->second );
}
}
CEntityTemplateCollection::~CEntityTemplateCollection()
{
for( int id = 0; id < PS_MAX_PLAYERS + 2; id++ )
for( TemplateMap::iterator it = m_templates[id].begin(); it != m_templates[id].end(); ++it )
delete( it->second );
}

View File

@ -1,75 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// EntityTemplateCollection.h
//
// Keeps tabs on the various types of entity that roam the world.
//
// General note: Template, Base Entity, and Entity Class are used more-or-less interchangably.
//
// Usage: g_EntityTemplateCollection.LoadTemplates(): loads all templates
// g_EntityTemplateCollection.GetTemplate(name): get a template by name
//
// EntityTemplateCollection will look at all subdirectiroes of entities/, but each template's
// name will only be its filename; thus, no two templates should have the same filename,
// but subdirectories can be created in entities/ to organize the files nicely.
#ifndef INCLUDED_ENTITYTEMPLATECOLLECTION
#define INCLUDED_ENTITYTEMPLATECOLLECTION
#include <vector>
#include <map>
#include "lib/file/vfs/vfs_path.h"
#include "ps/CStr.h"
#include "ps/Singleton.h"
#include "ps/Game.h"
#include "ps/Filesystem.h"
#define g_EntityTemplateCollection CEntityTemplateCollection::GetSingleton()
class CPlayer;
class CEntityTemplate;
class CEntityTemplateCollection : public Singleton<CEntityTemplateCollection>
{
// TODO: PS_MAX_PLAYERS doesn't seem to be an upper limit -
// "This may be overridden by system.cfg ("max_players")"
// - so we shouldn't use it here
static const size_t NULL_PLAYER = (PS_MAX_PLAYERS+1);
typedef STL_HASH_MAP<CStrW, CEntityTemplate*, CStrW_hash_compare> TemplateMap;
typedef STL_HASH_MAP<CStrW, VfsPath, CStrW_hash_compare> TemplateFilenameMap;
TemplateMap m_templates[PS_MAX_PLAYERS + 2];
TemplateFilenameMap m_templateFilenames;
public:
~CEntityTemplateCollection();
CEntityTemplate* GetTemplate( const CStrW& entityType, CPlayer* player = 0 );
// Load list of template filenames
int LoadTemplates();
void LoadFile( const VfsPath& path );
// Create a list of the names of all base entities, excluding template_*,
// for display in ScEd's entity-selection box.
void GetEntityTemplateNames( std::vector<CStrW>& names );
// Get all the templates owned by a specific player, which is useful for techs
void GetPlayerTemplates( CPlayer* player, std::vector<CEntityTemplate*>& dest );
};
#endif

View File

@ -1,156 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "EventHandlers.h"
#include "Entity.h"
CEventContactAction::CEventContactAction( CEntity* target, int action ) : CScriptEvent( L"contactAction", EVENT_CONTACT_ACTION, true)
{
m_target = target;
m_action = action;
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"action", &m_action );
}
CEventTargetExhausted::CEventTargetExhausted( CEntity* target, int action ) : CScriptEvent( L"targetExhausted", EVENT_TARGET_EXHAUSTED, true)
{
m_target = target;
m_action = action;
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"action", &m_action );
}
CEventStartConstruction::CEventStartConstruction( CEntity* target ) : CScriptEvent( L"startConstruction", EVENT_START_CONSTRUCTION, true)
{
m_target = target;
AddLocalProperty( L"target", &m_target );
}
CEventStartProduction::CEventStartProduction( int productionType, const CStrW& name )
: CScriptEvent( L"startProduction", EVENT_START_PRODUCTION, true)
{
m_productionType = productionType;
m_name = name;
m_time = -1;
AddLocalProperty( L"productionType", &m_productionType );
AddLocalProperty( L"name", &m_name );
AddLocalProperty( L"time", &m_time );
}
CEventFinishProduction::CEventFinishProduction( int productionType, const CStrW& name )
: CScriptEvent( L"finishProduction", EVENT_FINISH_PRODUCTION, true)
{
m_productionType = productionType;
m_name = name;
AddLocalProperty( L"productionType", &m_productionType );
AddLocalProperty( L"name", &m_name );
}
CEventCancelProduction::CEventCancelProduction( int productionType, const CStrW& name )
: CScriptEvent( L"cancelProduction", EVENT_CANCEL_PRODUCTION, true)
{
m_productionType = productionType;
m_name = name;
AddLocalProperty( L"productionType", &m_productionType );
AddLocalProperty( L"name", &m_name );
}
CEventTargetChanged::CEventTargetChanged( CEntity* target ) : CScriptEvent( L"targetChanged", EVENT_TARGET_CHANGED, false )
{
m_target = target;
m_defaultOrder = -1;
m_defaultAction = 0;
m_defaultCursor = L"arrow-default";
m_secondaryOrder = -1;
m_secondaryAction = 0;
m_secondaryCursor = L"arrow-default";
AddLocalProperty( L"target", &m_target, true );
AddLocalProperty( L"defaultOrder", &m_defaultOrder );
AddLocalProperty( L"defaultAction", &m_defaultAction );
AddLocalProperty( L"defaultCursor", &m_defaultCursor );
AddLocalProperty( L"secondaryOrder", &m_secondaryOrder );
AddLocalProperty( L"secondaryCursor", &m_secondaryCursor );
AddLocalProperty( L"secondaryAction", &m_secondaryAction );
}
CEventPrepareOrder::CEventPrepareOrder( CEntity* target, int orderType, int action, const CStrW& name)
: CScriptEvent( L"prepareOrder", EVENT_PREPARE_ORDER, true )
{
m_target = target;
m_orderType = orderType;
m_action = action;
m_name = name;
AddLocalProperty( L"target", &m_target, true );
AddLocalProperty( L"orderType", &m_orderType, true );
AddLocalProperty( L"action", &m_action );
AddLocalProperty( L"name", &m_name );
AddLocalProperty( L"notifyType", &m_notifyType );
AddLocalProperty( L"notifySource", &m_notifySource );
}
CEventOrderTransition::CEventOrderTransition( int orderPrevious, int orderCurrent, CEntity* target, CVector3D& worldPosition )
: CScriptEvent( L"orderTransition", EVENT_ORDER_TRANSITION, true )
{
m_orderPrevious = orderPrevious;
m_orderCurrent = orderCurrent;
if(target) {
m_target = target->me;
}
else {
m_target = HEntity();
}
m_worldPosition = worldPosition;
AddLocalProperty( L"orderPrevious", &m_orderPrevious, true );
AddLocalProperty( L"orderCurrent", &m_orderCurrent );
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"position", &m_worldPosition );
}
CEventNotification::CEventNotification( const CEntityOrder& order, int notifyType ) : CScriptEvent( L"notification", EVENT_NOTIFICATION, true )
{
m_notifyType = notifyType;
m_target = order.m_target_entity;
CVector3D convert( order.m_target_location.x, 0.0f, order.m_target_location.y );
m_location = convert;
AddLocalProperty( L"notifyType", &m_notifyType );
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"location", &m_location );
}
CFormationEvent::CFormationEvent( int type ) : CScriptEvent( L"formationEvent", EVENT_FORMATION, true )
{
(int&) m_formationEvent = type;
AddLocalProperty( L"formationEvent", &m_formationEvent );
}
CIdleEvent::CIdleEvent( const CEntityOrder& order, int notifyType ) : CScriptEvent( L"idleEvent", EVENT_IDLE, false )
{
m_notifyType = notifyType;
m_orderType = order.m_type;
m_target = order.m_target_entity;
CVector3D convert( order.m_target_location.x, 0.0f, order.m_target_location.y );
m_location = convert;
AddLocalProperty( L"notifyType", &m_notifyType );
AddLocalProperty( L"orderType", &m_orderType );
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"location", &m_location );
}

View File

@ -1,169 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// List of event handlers (for entities) the engine will call in to.
// Using integer tags should be ever-so-slightly faster than the hashmap lookup
// Also allows events to be renamed without affecting other code.
#ifndef INCLUDED_EVENTHANDLERS
#define INCLUDED_EVENTHANDLERS
#include "scripting/DOMEvent.h"
#include "maths/Vector3D.h"
#include "EntityOrders.h"
class CEventInitialize : public CScriptEvent
{
public:
CEventInitialize() : CScriptEvent( L"initialize", EVENT_INITIALIZE, true ) {}
};
class CEventDeath : public CScriptEvent
{
public:
CEventDeath() : CScriptEvent( L"death", EVENT_DEATH, false ) {}
};
/*
class CEventTick : public CScriptEvent
{
public:
CEventTick() : CScriptEvent( L"tick", EVENT_TICK, false ) {}
};
*/
class CEventContactAction : public CScriptEvent
{
CEntity* m_target;
int m_action;
public:
CEventContactAction( CEntity* target, int action );
};
class CEventTargetExhausted : public CScriptEvent
{
CEntity* m_target;
int m_action;
public:
CEventTargetExhausted( CEntity* target, int action );
};
class CEventStartConstruction : public CScriptEvent
{
CEntity* m_target;
public:
CEventStartConstruction( CEntity* target );
};
class CEventStartProduction : public CScriptEvent
{
int m_productionType;
CStrW m_name;
float m_time;
public:
CEventStartProduction( int productionType, const CStrW& name );
inline float GetTime() { return m_time; }
};
class CEventFinishProduction : public CScriptEvent
{
int m_productionType;
CStrW m_name;
public:
CEventFinishProduction( int productionType, const CStrW& name );
};
class CEventCancelProduction : public CScriptEvent
{
int m_productionType;
CStrW m_name;
public:
CEventCancelProduction( int productionType, const CStrW& name );
};
class CEventTargetChanged : public CScriptEvent
{
CEntity* m_target;
public:
int m_defaultOrder;
int m_defaultAction;
CStrW m_defaultCursor;
CStrW m_secondaryCursor;
int m_secondaryOrder;
int m_secondaryAction;
CEventTargetChanged( CEntity* target );
};
class CEventPrepareOrder : public CScriptEvent
{
public:
CEntity* m_target;
int m_orderType;
int m_action;
CStrW m_name;
CEntity* m_notifySource;
int m_notifyType;
CEventPrepareOrder( CEntity* target, int orderType, int action, const CStrW& name );
};
class CEventOrderTransition : public CScriptEvent
{
int m_orderPrevious;
int m_orderCurrent;
HEntity m_target;
CVector3D m_worldPosition;
public:
CEventOrderTransition( int orderPrevious, int orderCurrent, CEntity* target, CVector3D& worldPosition );
};
class CEventNotification : public CScriptEvent
{
//Same as CEntityOrder data for support of all orders
CEntity* m_target;
int m_action; //u64 is unsupported...will this work?
int m_notifyType;
CVector3D m_location; //No real use for y, but CVector2D unsupported
public:
CEventNotification( const CEntityOrder& order, int notifyType );
};
class CFormationEvent : public CScriptEvent
{
int m_formationEvent;
public:
CFormationEvent( int type );
enum FormationEventType
{
FORMATION_ENTER,
FORMATION_LEAVE,
FORMATION_DAMAGE,
FORMATION_ATTACK,
FORMATION_LAST
};
};
class CIdleEvent : public CScriptEvent
{
int m_notifyType; //previous order in notification code form
int m_orderType;
int m_action; //previous order in terms of generic order action
CVector3D m_location;
CEntity* m_target;
public:
CIdleEvent( const CEntityOrder& order, int notifyType );
};
#endif

View File

@ -21,9 +21,9 @@
#include "ps/Game.h"
#include "ps/Player.h"
#include "ps/World.h"
#include "graphics/Terrain.h"
#include "Entity.h"
#include "EntityManager.h"
#include "EntityTemplate.h"
#include "graphics/Unit.h"
#include "maths/Bound.h"
@ -136,7 +136,7 @@ void CLOSManager::Update()
// Set visibility for each entity
std::vector<CEntity*> extant;
g_EntityManager.GetExtant(extant);
// g_EntityManager.GetExtant(extant);
for(size_t i=0; i<extant.size(); i++)
{
CEntity* e = extant[i];

View File

@ -1,658 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ps/Profile.h"
#include "EntityOrders.h"
#include "Entity.h"
#include "EntityTemplate.h"
#include "PathfindEngine.h"
#include "graphics/Terrain.h"
#include "ps/World.h"
#include "ps/GameSetup/Config.h"
#include "lib/ogl.h"
#ifdef USE_DCDT
#define EPSILON 0.00001f
class TriangulationTerrainOverlay : public TerrainOverlay
{
SrArray<SrPnt2> constr;
SrArray<SrPnt2> unconstr;
//std::vector<CVector2D> path;
SrPolygon CurPath;
public:
void RenderCurrentPath()
{
glColor3f(1,1,1);
for(int i=0; i< CurPath.size()-1; i++)
{
std::vector<CEntity*> results;
g_EntityManager.GetExtant(results);
CEntity* tempHandle = results[0];
glBegin(GL_LINE_LOOP);
float x1 = CurPath[i].x;
float y1 = CurPath[i].y;
float x2 = CurPath[i+1].x;
float y2 = CurPath[i+1].y;
glVertex3f(x1,tempHandle->GetAnchorLevel(x1,y1) + 0.2f,y1);
glVertex3f(x2,tempHandle->GetAnchorLevel(x2,y2) + 0.2f,y2);
glEnd();
}
}
//
//Kai: added function to draw out constrained line segments in triangulation
//
void RenderConstrainedEdges()
{
std::vector<CEntity*> results;
g_EntityManager.GetExtant(results);
CEntity* tempHandle = results[0];
glColor3f( 1, 1, 1 );
for(int i=0; i<constr.size()-2; i=i+2)
{
glBegin( GL_LINE_LOOP );
SrPnt2 p1 = constr[i];
SrPnt2 p2 = constr[i+1];
float x1 = p1.x;
float y1 = p1.y;
float x2 = p2.x;
float y2 = p2.y;
glVertex3f( x1, tempHandle->GetAnchorLevel( x1, y1 ) + 0.2f, y1 );
glVertex3f( x2, tempHandle->GetAnchorLevel( x2, y2 ) + 0.2f, y2 );
glEnd();
}
}
//
// Kai: added function to draw out unconstrained line segments in triangulation
//
void RenderUnconstrainedEdges()
{
std::vector<CEntity*> results;
g_EntityManager.GetExtant(results);
CEntity* tempHandle = results[0];
glColor3f( 0, 1, 0 );
for(int i=0; i<unconstr.size()-2; i=i+2)
{
glBegin( GL_LINE_LOOP );
SrPnt2 p1 = unconstr[i];
SrPnt2 p2 = unconstr[i+1];
float x1 = p1.x;
float y1 = p1.y;
float x2 = p2.x;
float y2 = p2.y;
glVertex3f( x1, tempHandle->GetAnchorLevel( x1, y1 ) + 0.2f, y1 );
glVertex3f( x2, tempHandle->GetAnchorLevel( x2, y2 ) + 0.2f, y2 );
glEnd();
}
}
void setCurrentPath(const SrPolygon& _CurPath)
{
CurPath = _CurPath;
}
void setConstrainedEdges(const SrArray<SrPnt2>& _constr)
{
constr = _constr;
}
void setUnconstrainedEdges(const SrArray<SrPnt2>& _unconstr)
{
unconstr = _unconstr;
}
void Render()
{
}
TriangulationTerrainOverlay()
{
}
virtual void GetTileExtents(
ssize_t& min_i_inclusive, ssize_t& min_j_inclusive,
ssize_t& max_i_inclusive, ssize_t& max_j_inclusive)
{
min_i_inclusive = 1;
min_j_inclusive = 1;
max_i_inclusive = 2;
max_j_inclusive = 2;
}
virtual void ProcessTile(ssize_t UNUSED(i), ssize_t UNUSED(j))
{
RenderConstrainedEdges();
RenderUnconstrainedEdges();
RenderCurrentPath();
}
};
#endif // USE_DCDT
#ifdef USE_DCDT
CPathfindEngine::CPathfindEngine() : triangulationOverlay(0),
OABBBOUNDREDUCTION(0.8f),
CIRCLEBOUNDREDUCTION(0.5f),
RADIUSINCREMENT(2.0f)
{
dcdtInitialized = false;
if (g_ShowPathfindingOverlay)
triangulationOverlay = new TriangulationTerrainOverlay();
}
CPathfindEngine::~CPathfindEngine()
{
if (triangulationOverlay)
{
delete triangulationOverlay;
triangulationOverlay = 0;
}
}
#else // USE_DCDT
CPathfindEngine::CPathfindEngine() { }
CPathfindEngine::~CPathfindEngine() { }
#endif // USE_DCDT
#ifdef USE_DCDT
//Todo:
// 1; the bouncing problem with the fortress
// 2; update obstacles when things vanishes. done
void CPathfindEngine::initBoundary()
{
SrPolygon boundary ;
CTerrain* m_Terrain = g_Game->GetWorld()->GetTerrain();
int width = m_Terrain->GetVerticesPerSide() * CELL_SIZE ;
boundary.push().set(0.0f, 0.0f);
boundary.push().set(width, 0.0f);
boundary.push().set(width, width);
boundary.push().set(0.0f, width);
dcdtPathfinder.init(boundary, EPSILON,1);
dcdtPathfinder.InitializeSectors();
}
void CPathfindEngine::insertObstacles()
{
std::vector<CEntity*> results;
g_EntityManager.GetExtant(results);
SrPolygon poly;
for(size_t i =0 ; i < results.size(); i++)
{
poly.size(0);
CEntity* tempHandle = results[i];
//debug_printf(L"Entity position: %f %f %f\n", tempHandle->m_position.X,tempHandle->m_position.Y,tempHandle->m_position.Z);
CVector2D p, q;
CVector2D u, v;
q.x = tempHandle->m_position.X;
q.y = tempHandle->m_position.Z;
float d = ((CBoundingBox*)tempHandle->m_bounds)->m_d;
float w = ((CBoundingBox*)tempHandle->m_bounds)->m_w;
u.x = sin( tempHandle->m_graphics_orientation.Y );
u.y = cos( tempHandle->m_graphics_orientation.Y );
v.x = u.y;
v.y = -u.x;
CBoundingObject* m_bounds = tempHandle->m_bounds;
switch( m_bounds->m_type )
{
case CBoundingObject::BOUND_CIRCLE:
{
if(tempHandle->m_speed == 0)
{
poly.open(false);
w = CIRCLEBOUNDREDUCTION;
d = CIRCLEBOUNDREDUCTION;
p = q + u * d + v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d + v * w ;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q + u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
int dcdtId = dcdtPathfinder.insert_polygon(poly);
tempHandle->m_dcdtId = dcdtId;
}
break;
}
case CBoundingObject::BOUND_OABB:
{
poly.open(false);
// Tighten the bound so the units will not get stuck near the buildings
//Note: the triangulation pathfinding code will not find a path for the unit if it is pushed into the bound of a unit.
//
w = w * OABBBOUNDREDUCTION;
d = d * OABBBOUNDREDUCTION;
p = q + u * d + v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d + v * w ;
poly.push().set((float)(p.x), (float)(p.y));
p = q - u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
p = q + u * d - v * w;
poly.push().set((float)(p.x), (float)(p.y));
int dcdtId = dcdtPathfinder.insert_polygon(poly);
tempHandle->m_dcdtId = dcdtId;
break;
}
}//end switch
}//end for loop
dcdtPathfinder.DeleteAbstraction();
dcdtPathfinder.Abstract();
}
void CPathfindEngine::drawTriangulation()
{
int polyNum = dcdtPathfinder.num_polygons();
//debug_printf(L"Number of polygons: %d",polyNum);
if(polyNum)
{
SrArray<SrPnt2> constrainedEdges;
SrArray<SrPnt2> unconstrainedEdges;
dcdtPathfinder.get_mesh_edges(&constrainedEdges, &unconstrainedEdges);
if (triangulationOverlay)
{
triangulationOverlay->setConstrainedEdges(constrainedEdges);
triangulationOverlay->setUnconstrainedEdges(unconstrainedEdges);
}
}
}
#endif // USE_DCDT
void CPathfindEngine::RequestPath( HEntity entity, const CVector2D& destination,
CEntityOrder::EOrderSource orderSource )
{
/* TODO: Add code to generate high level path
For now, just the one high level waypoint to the final
destination is added
*/
CEntityOrder waypoint;
waypoint.m_type = CEntityOrder::ORDER_GOTO_WAYPOINT;
waypoint.m_source = orderSource;
waypoint.m_target_location = destination;
waypoint.m_pathfinder_radius = 0.0f;
#ifdef USE_DCDT
//Kai: adding radius for pathfinding
CBoundingObject* m_bounds = entity->m_bounds;
waypoint.m_pathfinder_radius = m_bounds->m_radius + RADIUSINCREMENT;
#endif // USE_DCDT
entity->m_orderQueue.push_front( waypoint );
}
#ifdef USE_DCDT
void CPathfindEngine::RequestTriangulationPath( HEntity entity, const CVector2D& destination, bool contact,
float radius, CEntityOrder::EOrderSource orderSource )
{
PROFILE_START("Pathfinding");
CEntityOrder::EOrderType stepType = CEntityOrder::ORDER_GOTO_NOPATHING;
if (contact) stepType = CEntityOrder::ORDER_GOTO_NOPATHING_CONTACT;
if(g_TriPathfind)
{
/* TODO:1. add code to verify the triangulation. done.
2. add code to convert a path from dcdtpathfinder to world waypoints done
*/
if(!dcdtInitialized)
{
initBoundary();
insertObstacles();
dcdtInitialized =true;
//switch on/off triangulation drawing by command line arg "-showOverlay"
//it's guarded here to stop setting constrainedEdges and unconstrainedEdges in triangulationOverlay->
//(efficiency issue)
//the drawing is disable in the render() function in TerraiOverlay.cpp
if(g_ShowPathfindingOverlay)
{
drawTriangulation();
}
}
}
//Kai: added test for terrain information in entityManager
//mLowPathfinder.TAStarTest();
CVector2D source( entity->m_position.X, entity->m_position.Z );
bool found = mTriangulationPathfinder.FindPath(source, destination, entity,dcdtPathfinder, radius);
//push the path onto the order process queue.
SrPolygon CurPath;
SrPolygon CurChannel;
if ( !found )
{
// If no path was found, then unsolvable
// TODO: Figure out what to do in this case
CurPath.size(0);
CurChannel.size(0);
}
else
{
CurChannel = dcdtPathfinder.GetChannelBoundary();
CurPath = dcdtPathfinder.GetPath();
//set and draw the path on the terrain
if (triangulationOverlay)
{
triangulationOverlay->setCurrentPath(CurPath);
}
// Make the path take as few steps as possible by collapsing steps in the same direction together.
std::vector<CVector2D> path;
debug_printf(L"waypoints: %d channel size %d \n ",CurPath.size(),CurChannel.size());
for (int i = 0; i < CurPath.size(); i++)
{
CVector2D waypoint ;
waypoint.x = CurPath[i].x;
waypoint.y = CurPath[i].y;
debug_printf(L"waypoints: %f %f \n",waypoint.x, waypoint.y);
path.push_back(waypoint);
}
if( path.size() > 0 )
{
// Push the path onto the front of our order queue in reverse order,
// so that we run through it before continuing other orders.
CEntityOrder node;
node.m_source = orderSource;
// Hack to make pathfinding slightly more precise:
// If the radius was 0, make the final node be exactly at the destination
// (otherwise, go to wherever the pathfinder tells us since we just want to be in range)
CVector2D finalDest = (radius==0 ? destination : path[path.size()-1]);
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER; // push end marker (used as a sentinel when repathing)
node.m_target_location = finalDest;
entity->m_orderQueue.push_front(node);
node.m_type = stepType; // push final goto step
node.m_target_location = finalDest;
entity->m_orderQueue.push_front(node);
for( int i = ((int) path.size()) - 2; i >= 0; i-- )
{
node.m_type = stepType; // TODO: For non-contact paths, do we want some other order type?
node.m_target_location = path[i];
entity->m_orderQueue.push_front(node);
}
}
else {
// Hack to make pathfinding slightly more precise:
// If radius = 0, we have an empty path but the user still wants us to move
// within the same tile, so add a GOTO order anyway
if(radius == 0)
{
CEntityOrder node;
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
node.m_target_location = destination;
entity->m_orderQueue.push_front(node);
node.m_type = stepType;
node.m_target_location = destination;
entity->m_orderQueue.push_front(node);
}
}
}
PROFILE_END("Pathfinding");
}
#endif // USE_DCDT
void CPathfindEngine::RequestLowLevelPath( HEntity entity, const CVector2D& destination, bool contact,
float radius, CEntityOrder::EOrderSource orderSource )
{
PROFILE_START("Pathfinding");
CEntityOrder::EOrderType stepType = CEntityOrder::ORDER_GOTO_NOPATHING;
if (contact) stepType = CEntityOrder::ORDER_GOTO_NOPATHING_CONTACT;
//Kai: added test for terrain information in entityManager
//mLowPathfinder.TAStarTest();
CVector2D source( entity->m_position.X, entity->m_position.Z );
if ( mLowPathfinder.FindPath(source, destination, entity, radius) )
{
std::vector<CVector2D> stepwisePath = mLowPathfinder.GetLastPath();
// Make the path take as few steps as possible by collapsing steps in the same direction together.
std::vector<CVector2D> path;
CVector2D lastDir(0, 0);
for(size_t i=0; i < stepwisePath.size(); i++)
{
if(i >= 2 && stepwisePath[i]-stepwisePath[i-1] == lastDir)
// We're in a colinear range; just update last point
path[path.size()-1] = stepwisePath[i];
else
path.push_back(stepwisePath[i]);
if(i >= 1)
lastDir = stepwisePath[i] - stepwisePath[i-1];
}
if( path.size() > 0 )
{
// Push the path onto the front of our order queue in reverse order,
// so that we run through it before continuing other orders.
CEntityOrder node;
node.m_source = orderSource;
// Hack to make pathfinding slightly more precise:
// If the radius was 0, make the final node be exactly at the destination
// (otherwise, go to wherever the pathfinder tells us since we just want to be in range)
CVector2D finalDest = (radius==0 ? destination : path[path.size()-1]);
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER; // push end marker (used as a sentinel when repathing)
node.m_target_location = finalDest;
entity->m_orderQueue.push_front(node);
node.m_type = stepType; // push final goto step
node.m_target_location = finalDest;
entity->m_orderQueue.push_front(node);
for( int i = ((int) path.size()) - 2; i >= 0; i-- )
{
node.m_type = stepType;
node.m_target_location = path[i];
entity->m_orderQueue.push_front(node);
}
}
else {
// Hack to make pathfinding slightly more precise:
// If radius = 0, we have an empty path but the user still wants us to move
// within the same tile, so add a GOTO order anyway
if(radius == 0)
{
CEntityOrder node;
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
node.m_target_location = destination;
entity->m_orderQueue.push_front(node);
node.m_type = stepType;
node.m_target_location = destination;
entity->m_orderQueue.push_front(node);
}
}
}
else
{
// If no path was found, then unsolvable
// TODO: Figure out what to do in this case
}
PROFILE_END("Pathfinding");
}
void CPathfindEngine::RequestContactPath( HEntity entity, CEntityOrder* current, float range )
{
/* TODO: Same as non-contact: need high-level planner */
CEntityOrder waypoint;
waypoint.m_type = CEntityOrder::ORDER_GOTO_WAYPOINT_CONTACT;
waypoint.m_source = current->m_source;
HEntity target = current->m_target_entity;
waypoint.m_target_location = target->m_position;
waypoint.m_pathfinder_radius = std::max( target->m_bounds->m_radius, range );
entity->m_orderQueue.push_front( waypoint );
//PathSparse( entity, current->m_target_entity->m_position );
//// For attack orders, do some additional postprocessing (replace goto/nopathing
//// with attack/nopathing, up until the attack order marker)
//std::deque<CEntityOrder>::iterator it;
//for( it = entity->m_orderQueue.begin(); it != entity->m_orderQueue.end(); it++ )
//{
// if( it->m_type == CEntityOrder::ORDER_PATH_END_MARKER )
// break;
// if( it->m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
// {
// *it = *current;
// }
//}
}
bool CPathfindEngine::RequestAvoidPath( HEntity entity, CEntityOrder* current, float avoidRange )
{
/* TODO: Same as non-contact: need high-level planner */
// TODO: Replace this with a new type of goal which is to avoid some point or line segment
// (requires changes to pathfinder to support this type of goal)
CEntityOrder waypoint;
waypoint.m_type = CEntityOrder::ORDER_GOTO_WAYPOINT_CONTACT;
waypoint.m_source = current->m_source;
// Figure out a direction to move
HEntity target = current->m_target_entity;
CVector3D dir = entity->m_position - target->m_position;
if(dir.LengthSquared() == 0) // shouldn't happen, but just in case
dir = CVector3D(1, 0, 0);
float dist = dir.Length();
dir.Normalize();
waypoint.m_target_location = entity->m_position + dir * (avoidRange - dist);
if( !g_Game->GetWorld()->GetTerrain()->IsOnMap( waypoint.m_target_location ) )
{
return false;
}
waypoint.m_pathfinder_radius = 0.0f;
entity->m_orderQueue.push_front( waypoint );
return true;
}

View File

@ -1,101 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// PathfindEngine.h
//
// The pathfinding engine singleton.
//
// Usage: g_Pathfinder.RequestPath( HEntity me, float x, float y );
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#ifndef INCLUDED_PATHFINDENGINE
#define INCLUDED_PATHFINDENGINE
#include "ps/Singleton.h"
#include "EntityHandles.h"
#include "ps/Vector2D.h"
#include "AStarEngine.h"
#ifdef USE_DCDT
# include "dcdt/se/se_dcdt.h"
# include "TRAStarEngine.h"
class TriangulationTerrainOverlay;
#endif // USE_DCDT
#define g_Pathfinder CPathfindEngine::GetSingleton()
class CEntityOrder;
enum EPathType
{
PF_STANDARD,
PF_ATTACK_MELEE,
};
class CPathfindEngine : public Singleton<CPathfindEngine>
{
NONCOPYABLE(CPathfindEngine);
public:
#ifdef USE_DCDT
//Kai: added for dcdt
const float OABBBOUNDREDUCTION ;
const float CIRCLEBOUNDREDUCTION ;
const float RADIUSINCREMENT ;
static SrArray<SeBase*> processing;
bool dcdtInitialized;
SeDcdt dcdtPathfinder;
void initBoundary();
void insertObstacles();
void drawTriangulation();
//Kai:added tile overlay for pathfinding
TriangulationTerrainOverlay* triangulationOverlay;
#endif
CPathfindEngine();
~CPathfindEngine();
void RequestPath( HEntity entity, const CVector2D& destination,
CEntityOrder::EOrderSource orderSource );
void RequestLowLevelPath( HEntity entity, const CVector2D& destination, bool contact,
float radius, CEntityOrder::EOrderSource orderSource );
void RequestContactPath( HEntity entity, CEntityOrder* current, float range );
bool RequestAvoidPath( HEntity entity, CEntityOrder* current, float avoidRange );
#ifdef USE_DCDT
void RequestTriangulationPath( HEntity entity, const CVector2D& destination, bool contact,
float radius, CEntityOrder::EOrderSource orderSource );
#endif
private:
CAStarEngineLowLevel mLowPathfinder;
#ifdef USE_DCDT
CTRAStarEngine mTriangulationPathfinder;
#endif
};
#endif

View File

@ -1,280 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "PathfindSparse.h"
#include "graphics/Terrain.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "Entity.h"
int SPF_RECURSION_DEPTH = 10;
SparsePathTree::SparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject, int _recursionDepth )
{
from = _from; to = _to;
recursionDepth = _recursionDepth;
entity = _entity; destinationCollisionObject = _destinationCollisionObject;
leftPre = NULL; leftPost = NULL;
rightPre = NULL; rightPost = NULL;
type = SPF_OPEN_UNVISITED;
leftImpossible = false; rightImpossible = false;
nextSubtree = 0;
}
SparsePathTree::~SparsePathTree()
{
if( leftPre ) delete( leftPre );
if( leftPost ) delete( leftPost );
if( rightPre ) delete( rightPre );
if( rightPost ) delete( rightPost );
}
bool SparsePathTree::slice()
{
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
if( type == SPF_OPEN_UNVISITED )
{
if( !recursionDepth )
{
// Too deep.
type = SPF_IMPOSSIBLE;
return( true );
}
rayIntersectionResults r;
CVector2D forward = to - from;
float len = forward.Length();
if( len == 0.0f )
{
// Too weird. (Heavy traffic, obstacles in positions leading to this degenerate state.
type = SPF_IMPOSSIBLE;
return( true );
}
forward /= len;
CVector2D v_right = CVector2D( forward.y, -forward.x );
if( !GetRayIntersection( from, forward, v_right, len, entity->m_bounds->m_radius * 1.1f, destinationCollisionObject, &r ) )
{
type = SPF_CLOSED_DIRECT;
return( true );
}
float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
if( entity->m_turningRadius > turningRadius ) turningRadius = entity->m_turningRadius;
// Too close, an impossible turn
if( r.distance < turningRadius )
{
// Too close to make a proper turn; try dodging immediately a long way to the left or right.
left = from - v_right * r.boundingObject->m_radius * 2.5f;
right = from + v_right * r.boundingObject->m_radius * 2.5f;
}
else if( r.distance > ( len - turningRadius ) )
{
// Again, too close to avoid it properly. Try approaching the goal from the left or right.
left = to - v_right * r.boundingObject->m_radius * 2.5f;
right = to + v_right * r.boundingObject->m_radius * 2.5f;
}
else
{
// Dodge to the left or right of the obstacle.
// A distance of offsetDistance is sufficient to guarantee we'll make the turn.
CVector2D delta = r.position - from;
float length = delta.Length();
float offsetDistance = ( turningRadius * length / sqrt( length * length - turningRadius * turningRadius ) );
left = r.position - v_right * offsetDistance;
right = r.position + v_right * offsetDistance;
}
favourLeft = false;
if( r.closestApproach < 0 )
favourLeft = true;
// First we path to the left...
leftPre = new SparsePathTree( from, left, entity, destinationCollisionObject, recursionDepth - 1 );
leftPost = new SparsePathTree( left, to, entity, destinationCollisionObject, recursionDepth - 1 );
// Then we path to the right...
rightPre = new SparsePathTree( from, right, entity, destinationCollisionObject, recursionDepth - 1 );
rightPost = new SparsePathTree( right, to, entity, destinationCollisionObject, recursionDepth - 1 );
// If anybody reaches this point and is thinking:
//
// "Let's Do The Time-Warp Agaaaain!"
//
// Let me know.
// Check that the subwaypoints are on the map...
if( !pTerrain->IsOnMap( left ) )
{
// Shut that path down
leftPre->type = SPF_IMPOSSIBLE;
leftPost->type = SPF_IMPOSSIBLE;
}
if( !pTerrain->IsOnMap( right ) )
{
// Shut that path down
rightPre->type = SPF_IMPOSSIBLE;
rightPost->type = SPF_IMPOSSIBLE;
}
if( ( leftPre->type == SPF_IMPOSSIBLE ) && ( rightPre->type == SPF_IMPOSSIBLE ) )
{
// It's unlikely, but I suppose it /might/ happen
type = SPF_IMPOSSIBLE;
return( true );
}
type = SPF_OPEN_PROCESSING;
return( true );
}
else /* type == SPF_OPEN_PROCESSING */
{
bool done = false;
while( !done )
{
if( subtrees[nextSubtree]->type & SPF_OPEN )
if( subtrees[nextSubtree]->slice() )
done = true;
nextSubtree++;
nextSubtree %= 4;
}
if( ( leftPre->type == SPF_IMPOSSIBLE ) || ( leftPost->type == SPF_IMPOSSIBLE ) )
leftImpossible = true;
if( ( rightPre->type == SPF_IMPOSSIBLE ) || ( rightPost->type == SPF_IMPOSSIBLE ) )
rightImpossible = true;
if( leftImpossible && rightImpossible )
{
type = SPF_IMPOSSIBLE;
return( done );
}
if( ( ( leftPre->type & SPF_SOLVED ) && ( leftPost->type & SPF_SOLVED ) ) ||
( ( rightPre->type & SPF_SOLVED ) && ( rightPost->type & SPF_SOLVED ) ) )
{
type = SPF_CLOSED_WAYPOINTED;
return( done );
}
return( done );
}
}
void SparsePathTree::pushResults( std::vector<CVector2D>& nodelist )
{
debug_assert( type & SPF_SOLVED );
if( type == SPF_CLOSED_DIRECT )
{
nodelist.push_back( to );
}
else /* type == SPF_CLOSED_WAYPOINTED */
{
leftImpossible = !( ( leftPre->type & SPF_SOLVED ) && ( leftPost->type & SPF_SOLVED ) );
rightImpossible = !( ( rightPre->type & SPF_SOLVED ) && ( rightPost->type & SPF_SOLVED ) );
if( !leftImpossible && ( favourLeft || rightImpossible ) )
{
leftPost->pushResults( nodelist );
leftPre->pushResults( nodelist );
}
else
{
debug_assert( !rightImpossible );
rightPost->pushResults( nodelist );
rightPre->pushResults( nodelist );
}
}
}
void NodePostProcess( HEntity entity, std::vector<CVector2D>& nodelist )
{
std::vector<CVector2D>::iterator it;
CVector2D next = nodelist.front();
CEntityOrder node;
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
entity->m_orderQueue.push_front( node );
node.m_type = CEntityOrder::ORDER_GOTO_SMOOTHED;
node.m_target_location = next;
entity->m_orderQueue.push_front( node );
for( it = nodelist.begin() + 1; it != nodelist.end(); it++ )
{
if( ( it + 1 ) == nodelist.end() ) break;
CVector2D current = *it;
CVector2D previous = *( it + 1 );
CVector2D u = current - previous;
CVector2D v = next - current;
u = u.Normalize();
v = v.Normalize();
CVector2D ubar = u.beta();
CVector2D vbar = v.beta();
float alpha = entity->m_turningRadius * ( ubar - vbar ).Length() / ( u + v ).Length();
node.m_target_location = current - u * alpha;
entity->m_orderQueue.push_front( node );
next = current;
}
// If we try to apply turning constraints to getting onto this path, there's a reasonable
// risk the entity will deviate so far from the first path segment that the path becomes
// unwalkable for it.
entity->m_orderQueue.front().m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
}
void PathSparse( HEntity entity, CVector2D destination )
{
std::vector<CVector2D> pathnodes;
CVector2D source( entity->m_position.X, entity->m_position.Z );
// Sanity check:
if( source.Length() < 0.01f ) return;
SparsePathTree sparseEngine( source, destination, entity, GetContainingObject( destination ), SPF_RECURSION_DEPTH );
while( sparseEngine.type & SparsePathTree::SPF_OPEN ) sparseEngine.slice();
// debug_assert( sparseEngine.type & SparsePathTree::SPF_SOLVED ); // Shouldn't be any impossible cases yet.
if( sparseEngine.type & SparsePathTree::SPF_SOLVED )
{
sparseEngine.pushResults( pathnodes );
pathnodes.push_back( source );
NodePostProcess( entity, pathnodes );
}
else
{
// Try a straight line. All we can do, really.
CEntityOrder direct;
direct.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
direct.m_target_location = destination;
entity->m_orderQueue.push_front( direct );
}
}

View File

@ -1,90 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// PathfindSparse.h
//
// Sparse pathfinder.
//
// Usage: You won't. See PathfindEngine.h
//
// Notes: A geometric pathfinder primarily for path postprocessing. Takes straight line
// paths and warps them to avoid obstacles.
// Sparse, because it runs in /exponential/ time with number of detours. Hence, only use
// where obstructions are sparse. You'll have fun if you try and path through, say,
// a forest with this.
//
// It also won't work at all through impassable terrain.
//
// TODO: Fix the algorithm for OABB obstacles.
// TODO: Replace with timesliced version and proper manager (either a singleton or tasks linked into g_Pathfinder)
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#ifndef INCLUDED_PATHFINDSPARSE
#define INCLUDED_PATHFINDSPARSE
#include "EntityHandles.h"
#include "ps/Vector2D.h"
#include "Collision.h"
struct SparsePathTree
{
enum
{
SPF_IMPOSSIBLE = 0,
SPF_OPEN_UNVISITED = 4,
SPF_OPEN_PROCESSING = 5,
SPF_CLOSED_DIRECT = 2,
SPF_CLOSED_WAYPOINTED = 3,
SPF_OPEN = 4,
SPF_SOLVED = 2
} type;
int recursionDepth;
HEntity entity;
CBoundingObject* destinationCollisionObject;
CVector2D from;
CVector2D to;
bool leftImpossible;
CVector2D left;
bool rightImpossible;
CVector2D right;
bool favourLeft;
union
{
struct
{
SparsePathTree* leftPre;
SparsePathTree* leftPost;
SparsePathTree* rightPre;
SparsePathTree* rightPost;
};
SparsePathTree* subtrees[4];
};
unsigned short nextSubtree;
SparsePathTree( const CVector2D& from, const CVector2D& to, HEntity entity, CBoundingObject* destinationCollisionObject, int _recursionDepth );
~SparsePathTree();
bool slice();
void pushResults( std::vector<CVector2D>& nodelist );
};
extern int SPF_RECURSION_DEPTH;
void NodePostProcess( HEntity entity, std::vector<CVector2D>& nodelist );
void PathSparse( HEntity entity, CVector2D destination );
bool PathSparseRecursive( HEntity entity, CVector2D from, CVector2D to, CBoundingObject* destinationCollisionObject );
#endif

View File

@ -1,163 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ProductionQueue.h"
#include "EntityManager.h"
#include "EventHandlers.h"
#include "Entity.h"
#include <algorithm>
// CProductionItem
CProductionItem::CProductionItem( int type, const CStrW& name, float totalTime )
: m_type(type), m_name(name), m_totalTime(totalTime), m_elapsedTime(0)
{
}
CProductionItem::~CProductionItem()
{
}
void CProductionItem::Update( int timestep )
{
m_elapsedTime = std::min( m_totalTime, m_elapsedTime + timestep/1000.0f );
}
bool CProductionItem::IsComplete()
{
return( m_elapsedTime == m_totalTime );
}
float CProductionItem::GetProgress()
{
return( m_totalTime==0 ? 1.0 : m_elapsedTime/m_totalTime );
}
jsval CProductionItem::JSI_GetProgress( JSContext* UNUSED(cx) )
{
return ToJSVal( GetProgress() );
}
void CProductionItem::ScriptingInit()
{
AddProperty(L"type", &CProductionItem::m_type, true);
AddProperty(L"name", &CProductionItem::m_name, true);
AddProperty(L"elapsedTime", &CProductionItem::m_elapsedTime, true);
AddProperty(L"totalTime", &CProductionItem::m_totalTime, true);
AddProperty(L"progress", static_cast<GetFn>(&CProductionItem::JSI_GetProgress));
CJSObject<CProductionItem>::ScriptingInit("ProductionItem");
}
// CProductionQueue
CProductionQueue::CProductionQueue( CEntity* owner )
: m_owner(owner)
{
}
CProductionQueue::~CProductionQueue()
{
CancelAll();
}
void CProductionQueue::AddItem( int type, const CStrW& name, float totalTime )
{
m_items.push_back( new CProductionItem( type, name, totalTime ) );
}
void CProductionQueue::CancelAll()
{
for( size_t i=0; i < m_items.size(); ++i )
{
// Cancel production of the item
CProductionItem* item = m_items[i];
CEventCancelProduction evt( item->m_type, item->m_name );
m_owner->DispatchEvent( &evt );
// Free its memory
delete m_items[i];
}
m_items.clear();
}
void CProductionQueue::Update( int timestep )
{
if( !m_items.empty() )
{
CProductionItem* front = m_items.front();
front->Update( timestep );
if( front->IsComplete() )
{
CEventFinishProduction evt( front->m_type, front->m_name );
m_owner->DispatchEvent( &evt );
m_items.erase( m_items.begin() );
delete front;
}
// TODO: Think about what we want to happen when there are multiple productions
// with totalTime=0 at the front (pop them all at once or do one per update?)
}
}
jsval CProductionQueue::JSI_GetLength( JSContext* UNUSED(cx) )
{
return ToJSVal( (int) m_items.size() );
}
jsval_t CProductionQueue::JSI_Get( JSContext* cx, uintN argc, jsval* argv )
{
debug_assert( argc == 1 );
debug_assert( JSVAL_IS_INT(argv[0]) );
int index = ToPrimitive<int>( argv[0] );
if(index < 0 || index >= (int)m_items.size() )
{
JS_ReportError( cx, "Production queue index out of bounds: %d", index );
return JSVAL_NULL;
}
return ToJSVal( m_items[index] );
}
bool CProductionQueue::JSI_Cancel( JSContext* cx, uintN argc, jsval* argv )
{
debug_assert( argc == 1 );
debug_assert( JSVAL_IS_INT(argv[0]) );
int index = ToPrimitive<int>( argv[0] );
if(index < 0 || index >= (int)m_items.size() )
{
JS_ReportError( cx, "Production queue index out of bounds: %d", index );
return false;
}
CProductionItem* item = m_items[index];
CEventCancelProduction evt( item->m_type, item->m_name );
m_owner->DispatchEvent( &evt );
m_items.erase( m_items.begin() + index );
return true;
}
void CProductionQueue::ScriptingInit()
{
AddProperty(L"length", static_cast<GetFn>(&CProductionQueue::JSI_GetLength));
AddMethod<jsval_t, &CProductionQueue::JSI_Get>( "get", 1 );
AddMethod<bool, &CProductionQueue::JSI_Cancel>( "cancel", 1 );
CJSObject<CProductionQueue>::ScriptingInit("ProductionQueue");
}

View File

@ -1,67 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PRODUCTIONQUEUE
#define INCLUDED_PRODUCTIONQUEUE
#include "EntityHandles.h"
#include "scripting/ScriptableObject.h"
#include <vector>
class CEntity;
class CProductionItem : public CJSObject<CProductionItem>
{
public:
int m_type;
CStrW m_name;
float m_totalTime; // how long this production takes
float m_elapsedTime; // how long we've been working on this production
CProductionItem( int type, const CStrW& name, float totalTime );
~CProductionItem();
void Update( int timestep );
bool IsComplete();
float GetProgress();
jsval JSI_GetProgress( JSContext* cx );
static void ScriptingInit();
};
class CProductionQueue : public CJSObject<CProductionQueue>
{
CEntity* m_owner;
std::vector<CProductionItem*> m_items;
public:
CProductionQueue( CEntity* owner );
~CProductionQueue();
void AddItem( int type, const CStrW& name, float totalTime );
void Update( int timestep );
void CancelAll();
jsval JSI_GetLength( JSContext* cx );
jsval_t JSI_Get( JSContext* cx, uintN argc, jsval* argv );
bool JSI_Cancel( JSContext* cx, uintN argc, jsval* argv );
static void ScriptingInit();
};
#endif

View File

@ -1,315 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Projectile.h"
#include "ScriptObject.h"
#include "graphics/GameView.h"
#include "graphics/Model.h"
#include "graphics/ObjectEntry.h"
#include "graphics/ObjectManager.h"
#include "graphics/Terrain.h"
#include "graphics/Unit.h"
#include "maths/Matrix3D.h"
#include "ps/CLogger.h"
#include "ps/Game.h"
#include "scripting/ScriptableComplex.inl"
#include "simulation/Collision.h"
#include "simulation/Entity.h"
const double GRAVITY = 0.00005;
const double GRAVITY_2 = GRAVITY * 0.5;
CProjectile::CProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript )
{
m_Actor = Actor->Clone();
m_Position = m_Position_Previous = m_Position_Graphics = Position;
m_Speed_H = Speed;
m_Originator = Originator;
m_ImpactEventHandler = ImpactScript;
m_MissEventHandler = MissScript;
AddHandler( EVENT_IMPACT, &m_ImpactEventHandler );
AddHandler( EVENT_MISS, &m_MissEventHandler );
// That was the easy stuff.
// We want horizontal distance only:
m_Axis = Target - Position;
double s = m_Axis.Length();
m_Axis /= (float)s;
// Now vertical distance:
double d_h = Target.Y - Position.Y;
// Time of impact:
double t = s / m_Speed_H;
// Required vertical velocity at launch:
m_Speed_V = (float)( d_h / t + GRAVITY_2 * t );
m_Speed_V_Previous = m_Speed_V;
}
CProjectile::~CProjectile()
{
//CProjectileManager& projectileManager = g_Game->GetWorld()->GetProjectileManager();
delete( m_Actor );
}
bool CProjectile::Update( int timestep_millis )
{
m_Position_Previous = m_Position;
m_Position.X += timestep_millis * m_Axis.x * m_Speed_H;
m_Position.Z += timestep_millis * m_Axis.y * m_Speed_H;
m_Position.Y += (float)( timestep_millis * ( m_Speed_V - timestep_millis * GRAVITY_2 ) );
m_Speed_V_Previous = m_Speed_V;
m_Speed_V -= (float)( timestep_millis * GRAVITY );
float height = m_Position.Y - g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel( m_Position.X, m_Position.Z );
if( height < 0.0f )
{
// We appear to have missed.
CEventProjectileMiss evt( m_Originator, m_Position );
DispatchEvent( &evt );
// Not going to let this be cancelled.
return( false );
}
RayIntersects& r = GetProjectileIntersection( m_Position_Previous, m_Axis, timestep_millis * m_Speed_H );
RayIntersects::iterator it;
for( it = r.begin(); it != r.end(); it++ )
{
// Hit something?
if( *it != m_Originator ) /* That wouldn't be fair at all... */
{
// Low enough to hit it?
if( height < (*it)->m_bounds->m_height )
{
CEventProjectileImpact evt( m_Originator, *it, m_Position );
if( DispatchEvent( &evt ) )
return( false );
}
}
}
return( true );
}
void CProjectile::Interpolate( int timestep_millis )
{
m_Position_Graphics.X = m_Position_Previous.X + timestep_millis * m_Speed_H * m_Axis.x;
m_Position_Graphics.Z = m_Position_Previous.Z + timestep_millis * m_Speed_H * m_Axis.y;
m_Position_Graphics.Y = (float)( m_Position_Previous.Y + timestep_millis * ( m_Speed_V_Previous - timestep_millis * GRAVITY_2 ) );
float dh_dt = (float)( m_Speed_V_Previous - timestep_millis * GRAVITY );
float scale = 1 / sqrt( m_Speed_H * m_Speed_H + dh_dt * dh_dt );
float scale2 = m_Speed_H * scale;
float y = dh_dt * scale;
CMatrix3D rotateInc;
rotateInc.SetIdentity();
rotateInc._22 = rotateInc._33 = y;
rotateInc._23 = -( rotateInc._32 = scale2 );
CMatrix3D rotateDir;
rotateDir.SetIdentity();
rotateDir._11 = rotateDir._33 = m_Axis.y;
rotateDir._31 = -( rotateDir._13 = m_Axis.x );
rotateInc.Concatenate( rotateDir );
rotateInc._14 = m_Position_Graphics.X;
rotateInc._24 = m_Position_Graphics.Y;
rotateInc._34 = m_Position_Graphics.Z;
m_Actor->SetTransform( rotateInc );
}
void CProjectile::ScriptingInit()
{
CJSObject<CProjectile>::ScriptingInit( "Projectile", Construct, 4 );
}
JSBool CProjectile::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
debug_assert( argc >= 4 );
CStrW ModelString;
CVector3D Here, There;
float Speed;
CEntity* Temp, *Originator = NULL;
CObjectEntry* oe = NULL;
CModel* Model = NULL;
CScriptObject Impact, Miss;
const char* err = NULL;
Temp = ToNative<CEntity>( argv[0] );
if(Temp)
{
// Model = Temp->m_actor->GetObject()->m_ProjectileModel;
if( !Model )
{
err = "No projectile model is defined for that entity's actor.";
goto fail;
}
}
else if( !ToPrimitive<CStrW>( cx, argv[0], ModelString ) || NULL == ( oe = g_Game->GetView()->GetObjectManager().FindObject( ModelString ) ) || NULL == ( Model = oe->m_Model ) )
{
err = "Invalid actor";
goto fail;
}
Temp = ToNative<CEntity>( argv[1] );
if(Temp)
{
// Use the position vector of this entity, add a bit (so the arrow doesn't appear out of the ground)
// In future, find the appropriate position from the entity (location of a specific prop point?)
Here = Temp->m_position;
Here.Y = g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel( Here.X, Here.Z ) + 2.5f;
}
else if( !( ToPrimitive<CVector3D>( cx, argv[1], Here ) ) )
{
err = "Invalid vector";
goto fail;
}
Temp = ToNative<CEntity>( argv[2] );
if(Temp)
{
// Use the position vector of this entity.
// TODO: Maybe: Correct for the movement of this entity.
// Then again, that doesn't belong here.
There = Temp->m_position;
There.Y = g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel( There.X, There.Z ) + 2.5f;
}
else if( !( ToPrimitive<CVector3D>( cx, argv[2], There ) ) )
{
err = "Invalid vector";
goto fail;
}
Speed = ToPrimitive<float>( cx, argv[3] );
if( Speed == 0.0f )
{
// Either wasn't specified, or was zero. In either case,
// can't allow it: div/0 errors in the physics
err = "Invalid speed";
goto fail;
}
// Ignore errors in these last few and use the defaults if there's a problem.
if( argc >= 5 )
Originator = ToNative<CEntity>( argv[4] );
if( argc >= 6 )
Impact = argv[5]; // Script to run on impact with an entity.
if( argc >= 7 )
Miss = argv[6]; // Script to run on impact with the floor.
{
CProjectile* p = g_Game->GetWorld()->GetProjectileManager()
.AddProjectile( Model, Here, There, Speed / 1000.0f, Originator, Impact, Miss );
*rval = ToJSVal<CProjectile>( *p );
return( JS_TRUE );
}
fail:
*rval = JSVAL_NULL;
JS_ReportError( cx, "%s", err );
return( JS_TRUE );
}
CEventProjectileImpact::CEventProjectileImpact( CEntity* Originator, CEntity* Impact, const CVector3D& Position ) : CScriptEvent( L"ProjectileImpact", EVENT_IMPACT )
{
m_Originator = Originator;
m_Impact = Impact;
m_Position = Position;
AddLocalProperty( L"originator", &m_Originator, true );
AddLocalProperty( L"impacted", &m_Impact );
AddLocalProperty( L"position", &m_Position );
}
CEventProjectileMiss::CEventProjectileMiss( CEntity* Originator, const CVector3D& Position ) : CScriptEvent( L"ProjectileMiss", EVENT_MISS )
{
m_Originator = Originator;
m_Position = Position;
AddLocalProperty( L"originator", &m_Originator, true );
AddLocalProperty( L"position", &m_Position );
}
CProjectileManager::CProjectileManager()
{
m_LastTurnLength = 0;
}
CProjectileManager::~CProjectileManager()
{
DeleteAll();
}
void CProjectileManager::DeleteAll()
{
std::list<CProjectile*>::iterator it;
for (it = m_Projectiles.begin(); it != m_Projectiles.end(); ++it)
{
delete *it;
}
m_Projectiles.clear();
}
CProjectile* CProjectileManager::AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript )
{
CProjectile* p = new CProjectile( Actor, Position, Target, Speed, Originator, ImpactScript, MissScript );
m_Projectiles.push_back( p );
return( p );
}
void CProjectileManager::DeleteProjectile( CProjectile* p )
{
m_Projectiles.erase( std::find(m_Projectiles.begin(), m_Projectiles.end(), p) );
delete p;
}
void CProjectileManager::UpdateAll( int timestep )
{
m_LastTurnLength = timestep;
std::list<CProjectile*>::iterator it;
for (it = m_Projectiles.begin(); it != m_Projectiles.end();)
{
CProjectile* p = *it;
if (!p->Update(timestep))
{
// Projectile is dead due to having hit the ground or something
std::list<CProjectile*>::iterator old = it;
it++;
m_Projectiles.erase(old);
delete p;
}
else
{
// Update completed successfully
it++;
}
}
}
void CProjectileManager::InterpolateAll( double relativeOffset )
{
int absoluteOffset = (int)( m_LastTurnLength * relativeOffset );
std::list<CProjectile*>::iterator it;
for( it = m_Projectiles.begin(); it != m_Projectiles.end(); ++it )
(*it)->Interpolate( absoluteOffset );
}

View File

@ -1,126 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
// Projectile.h
//
// Simple class that represents a single projectile in the simulation.
#ifndef INCLUDED_PROJECTILE
#define INCLUDED_PROJECTILE
#include <list>
#include "maths/Vector3D.h"
#include "ps/Vector2D.h"
#include "scripting/ScriptableObject.h"
#include "scripting/DOMEvent.h"
#include "ScriptObject.h"
#include "ps/Game.h"
#include "ps/World.h"
class CProjectileManager;
class CModel;
class CEntity;
class CProjectile : public CJSObject<CProjectile>, public IEventTarget
{
friend class CProjectileManager;
friend class CJSObject<CProjectile>;
CModel* m_Actor;
CVector3D m_Position;
CVector2D m_Axis;
CVector3D m_Position_Previous;
CVector3D m_Position_Graphics;
// Horizontal and vertical velocities
float m_Speed_H;
float m_Speed_V;
float m_Speed_V_Previous;
CEntity* m_Originator;
CScriptObject m_ImpactEventHandler;
CScriptObject m_MissEventHandler;
CProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript );
~CProjectile();
// Updates gameplay information for the specified timestep. Returns 'false' if the projectile should be removed from the world.
bool Update( int timestep_millis );
// Updates graphical information for a point timestep_millis after the previous simulation frame (and before the current one)
void Interpolate( int timestep_millis );
// Scripty things.
public:
static void ScriptingInit();
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSObject* GetScriptExecContext( IEventTarget* UNUSED(target) ) { return( GetScript() ); }
inline CModel* GetModel() const { return( m_Actor ); }
};
class CEventProjectileImpact : public CScriptEvent
{
CEntity* m_Originator;
CEntity* m_Impact;
CVector3D m_Position;
public:
CEventProjectileImpact( CEntity* Originator, CEntity* Impact, const CVector3D& Position );
};
class CEventProjectileMiss : public CScriptEvent
{
CEntity* m_Originator;
CVector3D m_Position;
public:
CEventProjectileMiss( CEntity* Originator, const CVector3D& Position );
};
// TODO: Maybe roll this (or at least the graphics bit) into the particle system?
// Initially this had g_UnitMan managing the models and g_EntityManager holding the
// projectiles themselves. This way may be less confusing - I'm not sure.
class CProjectileManager
{
friend class CProjectile;
public:
CProjectileManager();
~CProjectileManager();
void DeleteAll();
void UpdateAll( int timestep );
void InterpolateAll( double frametime );
inline const std::list<CProjectile*>& GetProjectiles() { return m_Projectiles; }
CProjectile* AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript );
// Only if you have some reason to prematurely get rid of a projectile.
// Under normal circumstances, it will delete itself when it hits something.
void DeleteProjectile( CProjectile* p );
private:
// Keep this so we can go from relative->absolute offsets in interpolate.
int m_LastTurnLength;
// Maintain a list of the projectiles in the world
std::list<CProjectile*> m_Projectiles;
};
#endif

View File

@ -38,7 +38,6 @@
#include "simulation/EntityManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/LOSManager.h"
#include "simulation/Projectile.h"
#include "simulation/Scheduler.h"
#include "simulation/Simulation.h"
#include "simulation/TerritoryManager.h"
@ -68,8 +67,8 @@ int CSimulation::Initialize(CGameAttributes* pAttribs)
g_ScriptingHost.RunScript( L"scripts/game_startup.js" );
// [2006-06-26 3647ms]
g_EntityManager.m_screenshotMode = pAttribs->m_ScreenshotMode;
g_EntityManager.InitializeAll();
// g_EntityManager.m_screenshotMode = pAttribs->m_ScreenshotMode;
// g_EntityManager.InitializeAll();
// [2006-06-26: 61ms]
m_pWorld->GetLOSManager()->Initialize((ELOSSetting)pAttribs->m_LOSSetting, pAttribs->m_FogOfWar);
@ -111,8 +110,7 @@ void CSimulation::Interpolate(double frameTime, double offset)
for (size_t i = 0; i < units.size(); ++i)
units[i]->UpdateModel((float)frameTime);
g_EntityManager.InterpolateAll(offset);
m_pWorld->GetProjectileManager().InterpolateAll(offset);
// g_EntityManager.InterpolateAll(offset);
}
void CSimulation::Simulate()

View File

@ -1,197 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Stance.h"
#include "EntityManager.h"
#include "Entity.h"
#include "ps/Player.h"
#include "graphics/Terrain.h"
#include <algorithm>
// AggressStance ////////////////////////////////////////////////////
void CAggressStance::OnIdle()
{
CEntity* target = CStanceUtils::ChooseTarget( m_Entity );
if( target )
CStanceUtils::Attack( m_Entity, target );
}
void CAggressStance::OnDamaged(CEntity *source)
{
if( source && m_Entity->m_orderQueue.empty()
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
CStanceUtils::Attack( m_Entity, source );
}
// StandStance //////////////////////////////////////////////////////
void CStandStance::OnIdle()
{
CEntity* target = CStanceUtils::ChooseTarget( m_Entity );
if( target )
CStanceUtils::Attack( m_Entity, target );
}
void CStandStance::OnDamaged(CEntity *source)
{
if( source && m_Entity->m_orderQueue.empty()
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
CStanceUtils::Attack( m_Entity, source );
}
// DefendStance /////////////////////////////////////////////////////
void CDefendStance::OnIdle()
{
idlePos = CVector2D( m_Entity->m_position.X, m_Entity->m_position.Z );
CEntity* target = CStanceUtils::ChooseTarget( m_Entity );
if( target )
CStanceUtils::Attack( m_Entity, target );
}
void CDefendStance::OnDamaged(CEntity *source)
{
if( source && m_Entity->m_orderQueue.empty()
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
{
// Retaliate only if we can reach the enemy unit without walking farther than our LOS
// radius away from idlePos.
int action = m_Entity->GetAttackAction( source->me );
if( action )
{
float range = m_Entity->m_actions[action].m_MaxRange;
if( ( range + m_Entity->m_los * CELL_SIZE ) >= m_Entity->Distance2D( source ) )
{
CEntityOrder order( CEntityOrder::ORDER_CONTACT_ACTION, CEntityOrder::SOURCE_UNIT_AI );
order.m_target_entity = source->me;
order.m_action = action;
order.m_run = false;
m_Entity->PushOrder( order );
}
}
}
}
bool CDefendStance::CheckMovement( CVector2D proposedPos )
{
float los = m_Entity->m_los*CELL_SIZE;
// Check that we haven't moved too far from the place where we were stationed.
if( (proposedPos - idlePos).Length() > los )
{
// TODO: Make sure we don't clear any player orders here; the best way would be to make
// shift-clicked player orders either unqueue any AI orders or convert those AI orders
// to player orders (since the player wants us to finish our attack then do other stuff).
m_Entity->m_orderQueue.clear();
// Try to find some other nearby enemy to attack, provided it's also in range of our idle spot
// TODO: really we should be attack-moving to our spot somehow
std::vector<CEntity*> results;
g_EntityManager.GetInRange( m_Entity->m_position.X, m_Entity->m_position.Z, los, results );
float bestDist = 1e20f;
CEntity* bestTarget = 0;
for( size_t i=0; i<results.size(); i++ )
{
CEntity* ent = results[i];
float range = m_Entity->m_actions[m_Entity->GetAttackAction(ent->me)].m_MaxRange;
if( m_Entity->GetPlayer()->GetDiplomaticStance( ent->GetPlayer() ) == DIPLOMACY_ENEMY )
{
float distToMe = ent->Distance2D( m_Entity );
float distToIdlePos = ent->Distance2D( idlePos );
if( distToIdlePos <= los+range && distToMe < bestDist )
{
bestDist = distToMe;
bestTarget = ent;
}
}
}
if( bestTarget != 0 )
{
CStanceUtils::Attack( m_Entity, bestTarget );
}
else
{
// Let's just walk back to our idle spot
CEntityOrder order( CEntityOrder::ORDER_GOTO, CEntityOrder::SOURCE_UNIT_AI );
order.m_target_location = idlePos;
m_Entity->PushOrder( order );
}
return false;
}
else
{
return true;
}
}
// StanceUtils //////////////////////////////////////////////////////
void CStanceUtils::Attack(CEntity* entity, CEntity* target)
{
int action = entity->GetAttackAction( target->me );
if( action )
{
CEntityOrder order( CEntityOrder::ORDER_CONTACT_ACTION, CEntityOrder::SOURCE_UNIT_AI );
order.m_target_entity = target->me;
order.m_action = action;
order.m_run = false;
entity->PushOrder( order );
}
}
CEntity* CStanceUtils::ChooseTarget( CEntity* entity )
{
return ChooseTarget( entity->m_position.X, entity->m_position.Z, entity->m_los*CELL_SIZE, entity->GetPlayer() );
}
CEntity* CStanceUtils::ChooseTarget( float x, float z, float radius, CPlayer* myPlayer )
{
std::vector<CEntity*> results;
g_EntityManager.GetInRange( x, z, radius, results );
float bestDist = 1e20f;
CEntity* bestTarget = 0;
for( size_t i=0; i<results.size(); i++ )
{
CEntity* ent = results[i];
if( myPlayer->GetDiplomaticStance( ent->GetPlayer() ) == DIPLOMACY_ENEMY )
{
float dist = ent->Distance2D( x, z );
if( dist < bestDist )
{
bestDist = dist;
bestTarget = ent;
}
}
}
return bestTarget;
}

View File

@ -1,130 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_STANCE
#define INCLUDED_STANCE
#include "ps/Vector2D.h"
class CEntity;
class CPlayer;
/**
* A combat stance. This object is given various events by an entity and can choose what the
* entity will do when it does not have any player orders.
**/
class CStance
{
protected:
CEntity* m_Entity;
public:
CStance(CEntity* ent): m_Entity(ent) {}
virtual ~CStance() {}
// Called each tick if the unit is idle.
virtual void OnIdle() = 0;
// Called when the unit is damaged. Source might be NULL for damage from "acts of Gaia"
// (but we get notified anyway in case we want to run around in fear). Most stances will
// probably want to retaliate here.
virtual void OnDamaged(CEntity* source) = 0;
// Does this stance allow movement at all during AI control?
virtual bool AllowsMovement() = 0;
// Called when the unit is under AI control and wishes to move to the given position;
// the stance may choose to cancel if it is too far.
virtual bool CheckMovement(CVector2D proposedPos) = 0;
};
/**
* Hold Fire stance: Unit never attacks, not even to fight back.
**/
class CHoldStance : public CStance
{
public:
CHoldStance(CEntity* ent): CStance(ent) {};
virtual ~CHoldStance() {};
virtual void OnIdle() {};
virtual void OnDamaged(CEntity* UNUSED(source)) {};
virtual bool AllowsMovement() { return false; };
virtual bool CheckMovement(CVector2D UNUSED(proposedPos)) { return false; }
};
/**
* Aggressive stance: The unit will attack any enemy it sees and pursue it indefinitely.
**/
class CAggressStance : public CStance
{
public:
CAggressStance(CEntity* ent): CStance(ent) {};
virtual ~CAggressStance() {};
virtual void OnIdle();
virtual void OnDamaged(CEntity* source);
virtual bool AllowsMovement() { return true; };
virtual bool CheckMovement(CVector2D UNUSED(proposedPos)) { return true; }
};
/**
* Stand Ground stance: The unit will attack enemies in LOS but never move.
**/
class CStandStance : public CStance
{
public:
CStandStance(CEntity* ent): CStance(ent) {};
virtual ~CStandStance() {};
virtual void OnIdle();
virtual void OnDamaged(CEntity* source);
virtual bool AllowsMovement() { return false; };
virtual bool CheckMovement(CVector2D UNUSED(proposedPos)) { return false; }
};
/**
* Defensive stance: The unit will attack enemies but will never pursue them further
* than its LOS away from its original position (the point where it last became idle).
**/
class CDefendStance : public CStance
{
CVector2D idlePos;
public:
CDefendStance(CEntity* ent): CStance(ent) {};
virtual ~CDefendStance() {};
virtual void OnIdle();
virtual void OnDamaged(CEntity* source);
virtual bool AllowsMovement() { return true; };
virtual bool CheckMovement(CVector2D proposedPos);
};
/**
* Utility functions used by the various stances.
**/
class CStanceUtils
{
private:
CStanceUtils() {};
public:
// Attacks the given target using the appropriate attack action (obtained from JavaScript).
static void Attack(CEntity* entity, CEntity* target);
// Picks a visible entity to attack.
static CEntity* ChooseTarget(CEntity* entity);
// Picks a visible entity within the given circle to attack
static CEntity* ChooseTarget(float x, float y, float radius, CPlayer* player);
};
#endif

View File

@ -1,40 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "TRAStarEngine.h"
#ifdef USE_DCDT
CTRAStarEngine::CTRAStarEngine(void)
{
mGoal = new AStarGoalLowLevel;
}
CTRAStarEngine::~CTRAStarEngine(void)
{
delete mGoal;
}
bool CTRAStarEngine::FindPath(const CVector2D &src, const CVector2D &dest, HEntity UNUSED(entity), SeDcdt& dcdtPathfinder, float radius )
{
bool found = dcdtPathfinder.SearchPathFast(src.x, src.y, dest.x, dest.y, radius);
return found;
}
#endif // USE_DCDT

View File

@ -1,39 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_TRASTARENGINE
#define INCLUDED_TRASTARENGINE
#ifdef USE_DCDT
#include "AStarEngine.h"
class CTRAStarEngine :
public CAStarEngine
{
public:
CTRAStarEngine(void);
~CTRAStarEngine(void);
SeDcdt dcdtPathfinder;;
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, SeDcdt& dcdtPathfinder,float radius=0.0f );
};
#endif // USE_DCDT
#endif

View File

@ -18,7 +18,6 @@
#include "precompiled.h"
#include "Technology.h"
#include "TechnologyCollection.h"
#include "EntityManager.h"
#include "ps/CStr.h"
#include "ps/CLogger.h"
#include "scripting/ScriptingHost.h"
@ -336,7 +335,7 @@ bool CTechnology::HasReqEntities()
// Check whether we have ALL the required entities.
std::vector<HEntity> entities;
m_player->GetControlledEntities(entities);
// m_player->GetControlledEntities(entities);
for ( std::vector<CStr>::iterator it=m_ReqEntities.begin(); it != m_ReqEntities.end(); it++ )
{
// For each required class, check that we have it
@ -466,7 +465,7 @@ bool CTechnology::ApplyEffects( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval
// Apply effects to all entities
std::vector<HEntity> entities;
m_player->GetControlledEntities(entities);
// m_player->GetControlledEntities(entities);
for ( size_t i=0; i<entities.size(); ++i )
{
Apply( entities[i] );

View File

@ -82,7 +82,7 @@ void CTerritoryManager::Recalculate()
// First, find all the units that are territory centres
std::vector<CEntity*> centres;
std::vector<CEntity*> entities;
g_EntityManager.GetExtant(entities);
// g_EntityManager.GetExtant(entities);
for( size_t i=0; i<entities.size(); i++ )
{
if( !entities[i]->entf_get(ENTF_DESTROYED) && entities[i]->m_base->m_isTerritoryCentre )

View File

@ -1,113 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "lib/timer.h"
#include "simulation/Scheduler.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/Entity.h"
#include "simulation/Projectile.h"
#include "simulation/EventHandlers.h"
#include "simulation/TriggerManager.h"
#include "simulation/FormationManager.h"
#include "simulation/FormationCollection.h"
#include "simulation/ProductionQueue.h"
#include "simulation/Technology.h"
#include "simulation/TechnologyCollection.h"
#include "simulation/PathfindEngine.h"
void SimulationScriptInit()
{
CJSProgressTimer::ScriptingInit();
CEntityTemplate::ScriptingInit();
CEntity::ScriptingInit();
CProjectile::ScriptingInit();
CTrigger::ScriptingInit();
CProductionItem::ScriptingInit();
CProductionQueue::ScriptingInit();
CTechnology::ScriptingInit();
EntityCollection::Init( "EntityCollection" );
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
g_ScriptingHost.DefineConstant( "NOTIFY_ATTACK", CEntityListener::NOTIFY_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_DAMAGE", CEntityListener::NOTIFY_DAMAGE );
g_ScriptingHost.DefineConstant( "NOTIFY_COMBAT", CEntityListener::NOTIFY_COMBAT );
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
g_ScriptingHost.DefineConstant( "ORDER_RUN", CEntityOrder::ORDER_RUN );
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
g_ScriptingHost.DefineConstant( "ORDER_CONTACT_ACTION", CEntityOrder::ORDER_CONTACT_ACTION );
g_ScriptingHost.DefineConstant( "ORDER_PRODUCE", CEntityOrder::ORDER_PRODUCE );
g_ScriptingHost.DefineConstant( "ORDER_SET_RALLY_POINT", CEntityOrder::ORDER_SET_RALLY_POINT );
g_ScriptingHost.DefineConstant( "ORDER_SET_STANCE", CEntityOrder::ORDER_SET_STANCE );
g_ScriptingHost.DefineConstant( "ORDER_START_CONSTRUCTION", CEntityOrder::ORDER_START_CONSTRUCTION );
}
void SimulationInit()
{
TIMER(L"SimulationInit");
new CEntityTemplateCollection;
new CFormationCollection;
new CTechnologyCollection;
g_EntityFormationCollection.LoadTemplates();
g_TechnologyCollection.LoadTechnologies();
new CFormationManager;
new CTriggerManager;
g_TriggerManager.LoadXml(L"scripts/TriggerSpecs.xml");
g_ScriptingHost.RunScript(L"scripts/trigger_functions.js");
// CEntityManager is managed by CWorld
//new CEntityManager;
new CPathfindEngine;
}
void SimulationShutdown()
{
TIMER_BEGIN(L"shutdown Pathfinder");
delete &g_Pathfinder;
TIMER_END(L"shutdown Pathfinder");
// Managed by CWorld
// delete &g_EntityManager;
delete &g_TriggerManager;
delete &g_FormationManager;
delete &g_TechnologyCollection;
delete &g_EntityFormationCollection;
delete &g_EntityTemplateCollection;
}

View File

@ -1,21 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
extern void SimulationScriptInit();
extern void SimulationInit();
extern void SimulationShutdown();

View File

@ -36,8 +36,6 @@
#include <iomanip>
bool g_UseSimulation2 = true;
class CSimulation2Impl
{
public:

View File

@ -37,9 +37,6 @@ class CMessage;
class SceneCollector;
class CFrustum;
// Hopefully-temporary flag for transition to new simulation system
extern bool g_UseSimulation2;
/**
* Public API for simulation system.
* Most code should interact with the simulation only through this API.

View File

@ -26,7 +26,6 @@
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "scripting/ScriptingHost.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation2/Simulation2.h"
class TestCmpPathfinder : public CxxTest::TestSuite
@ -34,8 +33,6 @@ class TestCmpPathfinder : public CxxTest::TestSuite
public:
void setUp()
{
g_UseSimulation2 = true;
CXeromyces::Startup();
g_VFS = CreateVfs(20 * MiB);
@ -47,13 +44,10 @@ public:
new CProfileViewer();
new CProfileManager();
new ScriptingHost();
new CEntityTemplateCollection();
g_EntityTemplateCollection.LoadTemplates();
}
void tearDown()
{
delete &g_EntityTemplateCollection;
delete &g_ScriptingHost;
delete &g_Profiler;
delete &g_ProfileViewer;
@ -62,8 +56,6 @@ public:
g_VFS.reset();
CXeromyces::Terminate();
g_UseSimulation2 = false;
}
// disabled by default; run tests with the "-test TestCmpPathfinder" flag to enable

View File

@ -26,7 +26,6 @@
#include "ps/Game.h"
#include "ps/World.h"
#include "maths/MathUtil.h"
#include "simulation/EntityManager.h"
#include "graphics/RenderableObject.h"
#include "../Brushes.h"
@ -136,21 +135,18 @@ BEGIN_COMMAND(AlterElevation)
}
g_Game->GetWorld()->GetTerrain()->MakeDirty(x0, y0, x0+g_CurrentBrush.m_W, y0+g_CurrentBrush.m_H, RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Undo()
{
m_TerrainDelta.Undo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Redo()
{
m_TerrainDelta.Redo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void MergeIntoPrevious(cAlterElevation* prev)
@ -195,21 +191,18 @@ BEGIN_COMMAND(FlattenElevation)
}
g_Game->GetWorld()->GetTerrain()->MakeDirty(x0, y0, x0+g_CurrentBrush.m_W, y0+g_CurrentBrush.m_H, RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Undo()
{
m_TerrainDelta.Undo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Redo()
{
m_TerrainDelta.Redo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void MergeIntoPrevious(cFlattenElevation* prev)

View File

@ -91,12 +91,6 @@ namespace
LDR_NonprogressiveLoad();
ret = g_Game->ReallyStartGame();
debug_assert(ret == PSRETURN_OK);
if (!g_UseSimulation2)
{
// Make sure entities get rendered in the correct location
g_Game->GetSimulation()->Interpolate(0.0);
}
}
}
@ -121,8 +115,7 @@ MESSAGEHANDLER(GenerateMap)
delete[] heightmap;
if (g_UseSimulation2)
AddDefaultPlayers();
AddDefaultPlayers();
// Start the game, load data files - this must be done before initialising
// the terrain texture below, since the terrains must be loaded before being

View File

@ -66,7 +66,7 @@ QUERYHANDLER(CinemaRecord)
int num_frames = msg->framerate * msg->duration;
View::GetView_Game()->SaveState(L"cinema_record", true);
View::GetView_Game()->SaveState(L"cinema_record");
// Set it to update the simulation at normal speed
View::GetView_Game()->SetSpeedMultiplier(1.f);
@ -123,7 +123,7 @@ QUERYHANDLER(Ping)
MESSAGEHANDLER(SimStateSave)
{
View::GetView_Game()->SaveState(*msg->label, msg->onlyentities);
View::GetView_Game()->SaveState(*msg->label);
}
MESSAGEHANDLER(SimStateRestore)

View File

@ -40,11 +40,6 @@
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/EntityTemplate.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
#include "simulation/TerritoryManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPosition.h"
@ -66,10 +61,7 @@ namespace
if (! unit)
return false;
if (unit->GetEntity())
return (unit->GetEntity()->m_base->m_anchorType != L"Ground");
else
return unit->GetObject().m_Base->m_Properties.m_FloatOnWater;
return unit->GetObject().m_Base->m_Properties.m_FloatOnWater;
}
CUnitManager& GetUnitManager()
@ -82,60 +74,26 @@ QUERYHANDLER(GetObjectsList)
{
std::vector<sObjectsListItem> objects;
if (g_UseSimulation2)
CmpPtr<ICmpTemplateManager> cmp(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (!cmp.null())
{
CmpPtr<ICmpTemplateManager> cmp(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (!cmp.null())
{
std::vector<std::wstring> names = cmp->FindAllTemplates();
std::vector<std::wstring> names = cmp->FindAllTemplates();
for (std::vector<std::wstring>::iterator it = names.begin(); it != names.end(); ++it)
{
sObjectsListItem e;
e.id = *it;
if (it->substr(0, 6) == L"actor|")
{
e.name = it->substr(6);
e.type = 1;
}
else
{
e.name = *it;
e.type = 0;
}
objects.push_back(e);
}
}
}
else
{
if (CEntityTemplateCollection::IsInitialised())
for (std::vector<std::wstring>::iterator it = names.begin(); it != names.end(); ++it)
{
std::vector<CStrW> names;
g_EntityTemplateCollection.GetEntityTemplateNames(names);
for (std::vector<CStrW>::iterator it = names.begin(); it != names.end(); ++it)
sObjectsListItem e;
e.id = *it;
if (it->substr(0, 6) == L"actor|")
{
//CEntityTemplate* baseent = g_EntityTemplateCollection.GetTemplate(*it);
sObjectsListItem e;
e.id = L"(e) " + *it;
e.name = *it; //baseent->m_Tag
e.type = 0;
objects.push_back(e);
}
}
{
std::vector<CStr> names;
//CObjectManager::GetPropObjectNames(names);
CObjectManager::GetAllObjectNames(names);
for (std::vector<CStr>::iterator it = names.begin(); it != names.end(); ++it)
{
sObjectsListItem e;
e.id = L"(n) " + CStrW(*it);
e.name = CStrW(*it).AfterFirst(/*L"props/"*/ L"actors/");
e.name = it->substr(6);
e.type = 1;
objects.push_back(e);
}
else
{
e.name = *it;
e.type = 0;
}
objects.push_back(e);
}
}
@ -153,9 +111,9 @@ void AtlasRenderSelection()
CUnit* unit = GetUnitManager().FindByID(g_Selection[i]);
if (unit)
{
if (unit->GetEntity())
if (false)
{
unit->GetEntity()->RenderSelectionOutline();
// TODO: should render footprint shape, if there is one
}
else
{
@ -332,9 +290,6 @@ private:
unit->SetPlayerID(player);
unit->SetActorSelections(selections);
if (m_PlayerOld != m_PlayerNew)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
}
};
END_COMMAND(SetObjectSettings);
@ -395,144 +350,52 @@ static bool ParseObjectName(const CStrW& obj, bool& isEntity, CStrW& name)
MESSAGEHANDLER(ObjectPreview)
{
if (g_UseSimulation2)
{
// If the selection has changed...
if (*msg->id != g_PreviewUnitName)
{
// Delete old entity
if (g_PreviewEntityID != INVALID_ENTITY)
g_Game->GetSimulation2()->DestroyEntity(g_PreviewEntityID);
// Create the new entity
if ((*msg->id).empty())
g_PreviewEntityID = INVALID_ENTITY;
else
g_PreviewEntityID = g_Game->GetSimulation2()->AddLocalEntity(L"preview|" + *msg->id);
g_PreviewUnitName = *msg->id;
}
if (g_PreviewEntityID != INVALID_ENTITY)
{
// Update the unit's position and orientation:
CmpPtr<ICmpPosition> cmpPos (*g_Game->GetSimulation2(), g_PreviewEntityID);
if (!cmpPos.null())
{
CVector3D pos = GetUnitPos(msg->pos, false);
cmpPos->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z));
float angle;
if (msg->usetarget)
{
// Aim from pos towards msg->target
CVector3D target = msg->target->GetWorldSpace(pos.Y);
angle = atan2(target.X-pos.X, target.Z-pos.Z);
}
else
{
angle = msg->angle;
}
cmpPos->SetYRotation(entity_angle_t::FromFloat(angle));
}
// TODO: handle random variations somehow
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), g_PreviewEntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(msg->settings->player);
}
return;
}
// Old simulation system:
CUnit* previewUnit = GetUnitManager().FindByID(g_PreviewUnitID);
// Don't recreate the unit unless it's changed
// If the selection has changed...
if (*msg->id != g_PreviewUnitName)
{
// Delete old unit
if (previewUnit)
{
GetUnitManager().DeleteUnit(previewUnit);
previewUnit = NULL;
}
// Delete old entity
if (g_PreviewEntityID != INVALID_ENTITY)
g_Game->GetSimulation2()->DestroyEntity(g_PreviewEntityID);
g_PreviewUnitID = invalidUnitId;
bool isEntity;
CStrW name;
if (ParseObjectName(*msg->id, isEntity, name))
{
std::set<CStr> selections; // TODO: get selections from user
// Create new unit
if (isEntity)
{
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate(name);
if (base) // (ignore errors)
{
previewUnit = GetUnitManager().CreateUnit(base->m_actorName, NULL, selections);
if (previewUnit)
{
g_PreviewUnitID = GetUnitManager().GetNewID();
previewUnit->SetID(g_PreviewUnitID);
}
g_PreviewUnitFloating = (base->m_anchorType != L"Ground");
// TODO: variations
}
}
else
{
previewUnit = GetUnitManager().CreateUnit(CStr(name), NULL, selections);
if (previewUnit)
{
g_PreviewUnitID = GetUnitManager().GetNewID();
previewUnit->SetID(g_PreviewUnitID);
}
g_PreviewUnitFloating = IsFloating(previewUnit);
}
}
// Create the new entity
if ((*msg->id).empty())
g_PreviewEntityID = INVALID_ENTITY;
else
g_PreviewEntityID = g_Game->GetSimulation2()->AddLocalEntity(L"preview|" + *msg->id);
g_PreviewUnitName = *msg->id;
}
if (previewUnit)
if (g_PreviewEntityID != INVALID_ENTITY)
{
// Update the unit's position and orientation:
CVector3D pos = GetUnitPos(msg->pos, g_PreviewUnitFloating);
float s, c;
if (msg->usetarget)
CmpPtr<ICmpPosition> cmpPos (*g_Game->GetSimulation2(), g_PreviewEntityID);
if (!cmpPos.null())
{
// Aim from pos towards msg->target
CVector3D target = msg->target->GetWorldSpace(pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
dir = dir.Normalize();
s = dir.x;
c = dir.y;
}
else
{
s = sin(msg->angle);
c = cos(msg->angle);
CVector3D pos = GetUnitPos(msg->pos, false);
cmpPos->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z));
float angle;
if (msg->usetarget)
{
// Aim from pos towards msg->target
CVector3D target = msg->target->GetWorldSpace(pos.Y);
angle = atan2(target.X-pos.X, target.Z-pos.Z);
}
else
{
angle = msg->angle;
}
cmpPos->SetYRotation(entity_angle_t::FromFloat(angle));
}
CMatrix3D m;
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = pos.X;
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = pos.Y;
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = pos.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
previewUnit->GetModel().SetTransform(m);
// TODO: handle random variations somehow
// Update the unit's player colour:
previewUnit->SetPlayerID(msg->settings->player);
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), g_PreviewEntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(msg->settings->player);
}
}
@ -564,138 +427,35 @@ BEGIN_COMMAND(CreateObject)
// TODO: variations too
m_Player = msg->settings->player;
if (!g_UseSimulation2)
{
// Get a new ID, for future reference to this unit
m_ID = GetUnitManager().GetNewID();
}
Redo();
}
void Redo()
{
if (g_UseSimulation2)
{
m_EntityID = g_Game->GetSimulation2()->AddEntity(*msg->id);
if (m_EntityID == INVALID_ENTITY)
return;
CmpPtr<ICmpPosition> cmpPos (*g_Game->GetSimulation2(), m_EntityID);
if (!cmpPos.null())
{
cmpPos->JumpTo(entity_pos_t::FromFloat(m_Pos.X), entity_pos_t::FromFloat(m_Pos.Z));
cmpPos->SetYRotation(entity_angle_t::FromFloat(m_Angle));
}
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), m_EntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(m_Player);
// TODO: handle random variations somehow
m_EntityID = g_Game->GetSimulation2()->AddEntity(*msg->id);
if (m_EntityID == INVALID_ENTITY)
return;
}
// Old simulation system:
bool isEntity;
CStrW name;
if (ParseObjectName(*msg->id, isEntity, name))
CmpPtr<ICmpPosition> cmpPos (*g_Game->GetSimulation2(), m_EntityID);
if (!cmpPos.null())
{
std::set<CStr> selections;
if (isEntity)
{
CEntityTemplate* base = g_EntityTemplateCollection.GetTemplate(name);
if (! base)
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to load entity template '%ls'", name.c_str());
else
{
HEntity ent = g_EntityManager.Create(base, m_Pos, m_Angle, selections);
if (! ent)
{
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to create entity of type '%ls'", name.c_str());
}
else if (! ent->m_actor)
{
// We don't want to allow entities with no actors, because
// they'll be be invisible and will confuse scenario designers
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to create entity of type '%ls'", name.c_str());
ent->Kill();
}
else
{
ent->m_actor->SetPlayerID(m_Player);
ent->m_actor->SetID(m_ID);
if (ent->m_base->m_isTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
ent->Initialize();
}
}
}
else
{
CUnit* unit = GetUnitManager().CreateUnit(CStr(name), NULL, selections);
if (! unit)
{
LOG(CLogger::Error, LOG_CATEGORY, L"Failed to load nonentity actor '%ls'", name.c_str());
}
else
{
unit->SetID(m_ID);
float s = sin(m_Angle);
float c = cos(m_Angle);
CMatrix3D m;
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = m_Pos.X;
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = m_Pos.Y;
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = m_Pos.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
unit->GetModel().SetTransform(m);
unit->SetPlayerID(m_Player);
}
}
cmpPos->JumpTo(entity_pos_t::FromFloat(m_Pos.X), entity_pos_t::FromFloat(m_Pos.Z));
cmpPos->SetYRotation(entity_angle_t::FromFloat(m_Angle));
}
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), m_EntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(m_Player);
// TODO: handle random variations somehow
}
void Undo()
{
if (g_UseSimulation2)
if (m_EntityID != INVALID_ENTITY)
{
if (m_EntityID != INVALID_ENTITY)
{
g_Game->GetSimulation2()->DestroyEntity(m_EntityID);
m_EntityID = INVALID_ENTITY;
}
return;
}
// Old simulation system:
CUnit* unit = GetUnitManager().FindByID(m_ID);
if (unit)
{
if (unit->GetEntity())
{
bool wasTerritoryCentre = unit->GetEntity()->m_base->m_isTerritoryCentre;
unit->GetEntity()->Kill();
if (wasTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
}
else
{
GetUnitManager().RemoveUnit(unit);
delete unit;
}
g_Game->GetSimulation2()->DestroyEntity(m_EntityID);
m_EntityID = INVALID_ENTITY;
}
}
};
@ -749,35 +509,15 @@ BEGIN_COMMAND(MoveObject)
void Do()
{
if (g_UseSimulation2)
{
m_PosNew = GetUnitPos(msg->pos, false); // TODO: set 'floating' properly
m_PosNew = GetUnitPos(msg->pos, false); // TODO: set 'floating' properly
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
m_PosOld = m_PosNew; // error
else
{
CFixedVector3D pos = cmpPos->GetPosition();
m_PosOld = CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat());
}
}
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
m_PosOld = m_PosNew; // error
else
{
CUnit* unit = GetUnitManager().FindByID(msg->id);
if (! unit) return;
m_PosNew = GetUnitPos(msg->pos, IsFloating(unit));
if (unit->GetEntity())
{
m_PosOld = unit->GetEntity()->m_position;
}
else
{
CMatrix3D m = unit->GetModel().GetTransform();
m_PosOld = m.GetTranslation();
}
CFixedVector3D pos = cmpPos->GetPosition();
m_PosOld = CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat());
}
SetPos(m_PosNew);
@ -785,34 +525,11 @@ BEGIN_COMMAND(MoveObject)
void SetPos(CVector3D& pos)
{
if (g_UseSimulation2)
{
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
cmpPos->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z));
}
else
{
CUnit* unit = GetUnitManager().FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
{
unit->GetEntity()->m_position = pos;
unit->GetEntity()->Teleport();
if (unit->GetEntity()->m_base->m_isTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
}
else
{
CMatrix3D m = unit->GetModel().GetTransform();
m.Translate(pos - m.GetTranslation());
unit->GetModel().SetTransform(m);
}
}
cmpPos->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z));
}
void Redo()
@ -838,116 +555,46 @@ END_COMMAND(MoveObject)
BEGIN_COMMAND(RotateObject)
{
float m_AngleOld, m_AngleNew;
CMatrix3D m_TransformOld, m_TransformNew;
void Do()
{
if (g_UseSimulation2)
{
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
m_AngleOld = cmpPos->GetRotation().Y.ToFloat();
if (msg->usetarget)
{
CMatrix3D transform = cmpPos->GetInterpolatedTransform(0.f);
CVector3D pos = transform.GetTranslation();
CVector3D target = msg->target->GetWorldSpace(pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
m_AngleNew = atan2(dir.x, dir.y);
}
else
{
m_AngleNew = msg->angle;
}
m_AngleOld = cmpPos->GetRotation().Y.ToFloat();
if (msg->usetarget)
{
CMatrix3D transform = cmpPos->GetInterpolatedTransform(0.f);
CVector3D pos = transform.GetTranslation();
CVector3D target = msg->target->GetWorldSpace(pos.Y);
m_AngleNew = atan2(target.X-pos.X, target.Z-pos.Z);
}
else
{
CUnit* unit = GetUnitManager().FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
{
m_AngleOld = unit->GetEntity()->m_orientation.Y;
if (msg->usetarget)
{
CVector3D& pos = unit->GetEntity()->m_position;
CVector3D target = msg->target->GetWorldSpace(pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
m_AngleNew = atan2(dir.x, dir.y);
}
else
{
m_AngleNew = msg->angle;
}
}
else
{
m_TransformOld = unit->GetModel().GetTransform();
CVector3D pos = unit->GetModel().GetTransform().GetTranslation();
float s, c;
if (msg->usetarget)
{
CVector3D target = msg->target->GetWorldSpace(pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
dir = dir.Normalize();
s = dir.x;
c = dir.y;
}
else
{
s = sinf(msg->angle);
c = cosf(msg->angle);
}
CMatrix3D& m = m_TransformNew;
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = pos.X;
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = pos.Y;
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = pos.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
}
m_AngleNew = msg->angle;
}
SetAngle(m_AngleNew, m_TransformNew);
SetAngle(m_AngleNew);
}
void SetAngle(float angle, CMatrix3D& transform)
void SetAngle(float angle)
{
if (g_UseSimulation2)
{
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
CmpPtr<ICmpPosition> cmpPos(*g_Game->GetSimulation2(), msg->id);
if (cmpPos.null())
return;
cmpPos->SetYRotation(entity_angle_t::FromFloat(angle));
}
else
{
CUnit* unit = GetUnitManager().FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
{
unit->GetEntity()->m_orientation.Y = angle;
unit->GetEntity()->Reorient();
}
else
{
unit->GetModel().SetTransform(transform);
}
}
cmpPos->SetYRotation(entity_angle_t::FromFloat(angle));
}
void Redo()
{
SetAngle(m_AngleNew, m_TransformNew);
SetAngle(m_AngleNew);
}
void Undo()
{
SetAngle(m_AngleOld, m_TransformOld);
SetAngle(m_AngleOld);
}
void MergeIntoPrevious(cRotateObject* prev)
@ -955,7 +602,6 @@ BEGIN_COMMAND(RotateObject)
// TODO: do something valid if prev unit != this unit
debug_assert(prev->msg->id == msg->id);
prev->m_AngleNew = m_AngleNew;
prev->m_TransformNew = m_TransformNew;
}
};
END_COMMAND(RotateObject)
@ -963,11 +609,6 @@ END_COMMAND(RotateObject)
BEGIN_COMMAND(DeleteObject)
{
// Old simulation: These two values are never both non-NULL
std::auto_ptr<SimState::Entity> m_FrozenEntity;
std::auto_ptr<SimState::Nonentity> m_FrozenNonentity;
// New simulation:
// Saved copy of the important aspects of a unit, to allow undo
entity_id_t m_EntityID;
std::wstring m_TemplateName;
@ -977,7 +618,7 @@ BEGIN_COMMAND(DeleteObject)
// TODO: random selections
cDeleteObject()
: m_FrozenEntity(NULL), m_FrozenNonentity(NULL), m_EntityID(INVALID_ENTITY), m_Owner(-1)
: m_EntityID(INVALID_ENTITY), m_Owner(-1)
{
}
@ -988,90 +629,46 @@ BEGIN_COMMAND(DeleteObject)
void Redo()
{
if (g_UseSimulation2)
CSimulation2& sim = *g_Game->GetSimulation2();
CmpPtr<ICmpTemplateManager> cmpTemplateManager(sim, SYSTEM_ENTITY);
debug_assert(!cmpTemplateManager.null());
m_EntityID = msg->id;
m_TemplateName = cmpTemplateManager->GetCurrentTemplateName(m_EntityID);
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
if (!cmpOwner.null())
m_Owner = cmpOwner->GetOwner();
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
if (!cmpPosition.null())
{
CSimulation2& sim = *g_Game->GetSimulation2();
CmpPtr<ICmpTemplateManager> cmpTemplateManager(sim, SYSTEM_ENTITY);
debug_assert(!cmpTemplateManager.null());
m_EntityID = msg->id;
m_TemplateName = cmpTemplateManager->GetCurrentTemplateName(m_EntityID);
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
if (!cmpOwner.null())
m_Owner = cmpOwner->GetOwner();
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
if (!cmpPosition.null())
{
m_Pos = cmpPosition->GetPosition();
m_Rot = cmpPosition->GetRotation();
}
g_Game->GetSimulation2()->DestroyEntity(m_EntityID);
return;
m_Pos = cmpPosition->GetPosition();
m_Rot = cmpPosition->GetRotation();
}
CUnit* unit = GetUnitManager().FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
{
bool wasTerritoryCentre = unit->GetEntity()->m_base->m_isTerritoryCentre;
m_FrozenEntity.reset(new SimState::Entity( SimState::Entity::Freeze(unit) ));
unit->GetEntity()->Kill();
if (wasTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
}
else
{
m_FrozenNonentity.reset(new SimState::Nonentity( SimState::Nonentity::Freeze(unit) ));
GetUnitManager().RemoveUnit(unit);
}
g_Game->GetSimulation2()->DestroyEntity(m_EntityID);
}
void Undo()
{
if (g_UseSimulation2)
CSimulation2& sim = *g_Game->GetSimulation2();
entity_id_t ent = sim.AddEntity(m_TemplateName, m_EntityID);
if (ent == INVALID_ENTITY)
LOGERROR(L"Failed to load entity template '%ls'", m_TemplateName.c_str());
else
{
CSimulation2& sim = *g_Game->GetSimulation2();
entity_id_t ent = sim.AddEntity(m_TemplateName, m_EntityID);
if (ent == INVALID_ENTITY)
LOGERROR(L"Failed to load entity template '%ls'", m_TemplateName.c_str());
else
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
if (!cmpPosition.null())
{
CmpPtr<ICmpPosition> cmpPosition(sim, m_EntityID);
if (!cmpPosition.null())
{
cmpPosition->JumpTo(m_Pos.X, m_Pos.Z);
cmpPosition->SetXZRotation(m_Rot.X, m_Rot.Z);
cmpPosition->SetYRotation(m_Rot.Y);
}
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(m_Owner);
cmpPosition->JumpTo(m_Pos.X, m_Pos.Z);
cmpPosition->SetXZRotation(m_Rot.X, m_Rot.Z);
cmpPosition->SetYRotation(m_Rot.Y);
}
return;
}
if (m_FrozenEntity.get())
{
CEntity* entity = m_FrozenEntity->Thaw();
if (entity && entity->m_base->m_isTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();
m_FrozenEntity.reset();
}
else if (m_FrozenNonentity.get())
{
m_FrozenNonentity->Thaw();
m_FrozenNonentity.reset();
CmpPtr<ICmpOwnership> cmpOwner(sim, m_EntityID);
if (!cmpOwner.null())
cmpOwner->SetOwner(m_Owner);
}
}
};

View File

@ -21,7 +21,6 @@
#include "../CommandProc.h"
#include "../Shareable.h"
#include "simulation/TriggerManager.h"
#include "ps/Game.h"
#include "graphics/GameView.h"
#include "graphics/CinemaTrack.h"
@ -29,6 +28,7 @@
namespace AtlasMessage {
/*
sTriggerSpec TriggerSpecToAtlas(const CTriggerSpec& spec)
{
sTriggerSpec atlasSpec;
@ -235,8 +235,7 @@ MapTriggerGroup AtlasToGroup(const sTriggerGroup& group)
std::vector<sTriggerGroup> GetCurrentTriggers()
{
if (g_UseSimulation2)
return std::vector<sTriggerGroup>();
return std::vector<sTriggerGroup>();
const std::list<MapTriggerGroup>& groups = g_TriggerManager.GetAllTriggerGroups();
std::vector<sTriggerGroup> atlasGroups;
@ -248,20 +247,17 @@ std::vector<sTriggerGroup> GetCurrentTriggers()
void SetCurrentTriggers(const std::vector<sTriggerGroup>& groups)
{
if (g_UseSimulation2)
return;
std::list<MapTriggerGroup> engineGroups;
for ( std::vector<sTriggerGroup>::const_iterator it = groups.begin(); it != groups.end(); ++it )
engineGroups.push_back( AtlasToGroup(*it) );
g_TriggerManager.SetAllGroups(engineGroups);
}
*/
QUERYHANDLER(GetTriggerData)
{
if (g_UseSimulation2)
return;
UNUSED2(msg);
/*
const std::list<CTriggerCondition>& conditions = g_TriggerManager.GetAllConditions();
const std::list<CTriggerEffect>& effects = g_TriggerManager.GetAllEffects();
std::vector<sTriggerSpec> atlasConditions;
@ -275,13 +271,13 @@ QUERYHANDLER(GetTriggerData)
msg->conditions = atlasConditions;
msg->effects = atlasEffects;
msg->groups = GetCurrentTriggers();
*/
}
QUERYHANDLER(GetTriggerChoices)
{
if (g_UseSimulation2)
return;
UNUSED2(msg);
/*
CStrW selectedName(*msg->name);
std::vector<std::wstring> choices = g_TriggerManager.GetTriggerChoices(selectedName);
std::vector<std::wstring> translations = g_TriggerManager.GetTriggerTranslations(selectedName);
@ -334,6 +330,7 @@ QUERYHANDLER(GetTriggerChoices)
}
msg->choices = choices;
msg->translations = translations;
*/
}
QUERYHANDLER(GetWorldPosition)
@ -347,21 +344,21 @@ QUERYHANDLER(GetWorldPosition)
}
BEGIN_COMMAND(SetAllTriggers)
{
std::vector<sTriggerGroup> m_oldGroups, m_newGroups;
// std::vector<sTriggerGroup> m_oldGroups, m_newGroups;
void Do()
{
m_oldGroups = GetCurrentTriggers();
m_newGroups = *msg->groups;
Redo();
// m_oldGroups = GetCurrentTriggers();
// m_newGroups = *msg->groups;
// Redo();
}
void Redo()
{
SetCurrentTriggers(m_newGroups);
// SetCurrentTriggers(m_newGroups);
}
void Undo()
{
SetCurrentTriggers(m_oldGroups);
// SetCurrentTriggers(m_oldGroups);
}
};
END_COMMAND(SetAllTriggers)

Some files were not shown because too many files have changed in this diff Show More