2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "graphics/GameView.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "graphics/Model.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "graphics/Sprite.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "graphics/Terrain.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "graphics/Unit.h"
|
|
|
|
#include "graphics/UnitManager.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "maths/MathUtil.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "maths/scripting/JSInterface_Vector3D.h"
|
|
|
|
#include "ps/Game.h"
|
|
|
|
#include "ps/Interact.h"
|
|
|
|
#include "ps/Profile.h"
|
|
|
|
#include "renderer/Renderer.h"
|
2006-01-07 02:04:26 +01:00
|
|
|
#include "renderer/WaterManager.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "scripting/ScriptableComplex.inl"
|
|
|
|
|
|
|
|
#include "Aura.h"
|
|
|
|
#include "Collision.h"
|
|
|
|
#include "Entity.h"
|
2006-03-31 05:30:34 +02:00
|
|
|
#include "EntityFormation.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "EntityManager.h"
|
|
|
|
#include "EntityTemplate.h"
|
|
|
|
#include "EntityTemplateCollection.h"
|
|
|
|
#include "EventHandlers.h"
|
2006-06-10 01:07:11 +02:00
|
|
|
#include "Formation.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "FormationManager.h"
|
|
|
|
#include "PathfindEngine.h"
|
|
|
|
#include "ProductionQueue.h"
|
2006-09-09 02:00:23 +02:00
|
|
|
#include "Stance.h"
|
2006-07-19 01:59:48 +02:00
|
|
|
#include "TechnologyCollection.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
#include "TerritoryManager.h"
|
2005-12-13 09:05:30 +01:00
|
|
|
|
2005-09-18 05:47:15 +02:00
|
|
|
#include <algorithm>
|
2006-09-26 03:44:20 +02:00
|
|
|
|
|
|
|
extern int g_xres, g_yres;
|
2005-09-18 05:47:15 +02:00
|
|
|
|
2006-07-30 00:02:11 +02:00
|
|
|
CEntity::CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStr8>& actorSelections, const CStrW* building )
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
2006-07-12 18:18:31 +02:00
|
|
|
ent_flags = 0;
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_position = position;
|
2006-07-18 06:17:46 +02:00
|
|
|
m_orientation.X = 0;
|
2006-07-20 16:37:58 +02:00
|
|
|
m_orientation.Y = orientation;
|
2006-07-18 06:17:46 +02:00
|
|
|
m_orientation.Z = 0;
|
2006-07-20 16:37:58 +02:00
|
|
|
m_ahead.x = sin( m_orientation.Y );
|
|
|
|
m_ahead.y = cos( m_orientation.Y );
|
|
|
|
m_position_previous = m_position;
|
|
|
|
m_orientation_previous = m_orientation;
|
2006-09-02 23:20:25 +02:00
|
|
|
m_player = NULL;
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2006-02-22 23:45:16 +01:00
|
|
|
m_productionQueue = new CProductionQueue( this );
|
2006-09-16 23:30:23 +02:00
|
|
|
m_stance = new CHoldStance( this );
|
2006-02-22 23:45:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
for( int t = 0; t < EVENT_LAST; t++ )
|
|
|
|
{
|
|
|
|
AddProperty( EventNames[t], &m_EventHandlers[t], false );
|
|
|
|
AddHandler( t, &m_EventHandlers[t] );
|
|
|
|
}
|
2006-04-12 08:37:51 +02:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_collisionPatch = NULL;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
// Set our parent unit and build us an actor.
|
|
|
|
m_actor = NULL;
|
|
|
|
m_bounds = NULL;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_lastState = -1;
|
|
|
|
entf_set(ENTF_TRANSITION);
|
|
|
|
m_fsm_cyclepos = NOT_IN_CYCLE;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_base = base;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-03-17 04:59:49 +01:00
|
|
|
m_actorSelections = actorSelections;
|
|
|
|
loadBase();
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_bounds )
|
|
|
|
m_bounds->setPosition( m_position.X, m_position.Z );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_graphics_position = m_position;
|
|
|
|
m_graphics_orientation = m_orientation;
|
2006-07-12 18:18:31 +02:00
|
|
|
m_actor_transform_valid = false;
|
|
|
|
entf_clear(ENTF_HAS_RALLY_POINT);
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_clear(ENTF_DESTROYED);
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_selected = false;
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_clear(ENTF_IS_RUNNING);
|
|
|
|
entf_clear(ENTF_SHOULD_RUN);
|
|
|
|
entf_clear(ENTF_TRIGGER_RUN);
|
2006-01-16 11:56:47 +01:00
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_clear(ENTF_HEALTH_DECAY);
|
2006-01-21 12:17:15 +01:00
|
|
|
|
2006-01-16 11:56:47 +01:00
|
|
|
m_frameCheck = 0;
|
2006-07-16 21:32:48 +02:00
|
|
|
m_lastCombatTime = -100;
|
|
|
|
m_lastRunTime = -100;
|
2006-02-13 04:32:15 +01:00
|
|
|
m_currentNotification = 0;
|
2006-04-09 00:34:54 +02:00
|
|
|
m_currentRequest = 0;
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_set(ENTF_DESTROY_NOTIFIERS);
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2006-04-22 07:52:23 +02:00
|
|
|
m_formationSlot = -1;
|
2006-03-31 05:30:34 +02:00
|
|
|
m_formation = -1;
|
2006-07-20 16:37:58 +02:00
|
|
|
m_grouped = -1;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-24 03:33:26 +02:00
|
|
|
if( building )
|
|
|
|
m_building = *building;
|
2006-07-09 00:40:01 +02:00
|
|
|
|
2006-07-13 02:16:11 +02:00
|
|
|
m_extant = true;
|
2006-07-10 01:12:37 +02:00
|
|
|
m_visible = true;
|
|
|
|
|
2006-09-17 04:20:20 +02:00
|
|
|
m_rallyPoint = m_position;
|
|
|
|
|
|
|
|
m_associatedTerritory = NULL;
|
2006-09-16 23:30:23 +02:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_player = g_Game->GetPlayer( 0 );
|
2004-06-11 00:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CEntity::~CEntity()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_actor )
|
|
|
|
{
|
2007-01-08 02:56:46 +01:00
|
|
|
g_Game->GetWorld()->GetUnitManager().RemoveUnit( m_actor );
|
2006-07-20 16:37:58 +02:00
|
|
|
delete( m_actor );
|
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_bounds )
|
|
|
|
{
|
|
|
|
delete( m_bounds );
|
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-02-22 23:45:16 +01:00
|
|
|
delete m_productionQueue;
|
|
|
|
|
2006-09-09 02:00:23 +02:00
|
|
|
delete m_stance;
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
for( AuraTable::iterator it = m_auras.begin(); it != m_auras.end(); it++ )
|
|
|
|
{
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
m_auras.clear();
|
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_set(ENTF_DESTROY_NOTIFIERS);
|
2006-04-09 00:34:54 +02:00
|
|
|
for ( size_t i=0; i<m_listeners.size(); i++ )
|
|
|
|
m_listeners[i].m_sender->DestroyNotifier( this );
|
2007-01-25 08:00:31 +01:00
|
|
|
m_listeners.clear();
|
2006-04-09 00:34:54 +02:00
|
|
|
DestroyAllNotifiers();
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2006-03-31 05:30:34 +02:00
|
|
|
CEntity* remove = this;
|
|
|
|
g_FormationManager.RemoveUnit(remove);
|
2004-06-11 00:24:03 +02:00
|
|
|
}
|
2005-01-23 23:32:10 +01:00
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
void CEntity::loadBase()
|
|
|
|
{
|
2007-01-27 03:36:33 +01:00
|
|
|
int previous_unit_id = -1;
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_actor )
|
|
|
|
{
|
2007-01-27 03:36:33 +01:00
|
|
|
previous_unit_id = m_actor->GetID();
|
2007-01-08 02:56:46 +01:00
|
|
|
g_Game->GetWorld()->GetUnitManager().RemoveUnit( m_actor );
|
2006-07-20 16:37:58 +02:00
|
|
|
delete( m_actor );
|
|
|
|
m_actor = NULL;
|
|
|
|
}
|
|
|
|
if( m_bounds )
|
|
|
|
{
|
|
|
|
delete( m_bounds );
|
|
|
|
m_bounds = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CStr actorName ( m_base->m_actorName ); // convert CStrW->CStr8
|
2006-03-17 04:59:49 +01:00
|
|
|
|
2007-01-08 02:56:46 +01:00
|
|
|
m_actor = g_Game->GetWorld()->GetUnitManager().CreateUnit( actorName, this, m_actorSelections );
|
2007-01-27 03:36:33 +01:00
|
|
|
if( m_actor )
|
|
|
|
m_actor->SetID( previous_unit_id );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
// Set up our instance data
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
SetBase( m_base );
|
|
|
|
m_classes.SetParent( &( m_base->m_classes ) );
|
|
|
|
SetNextObject( m_base );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
|
|
|
|
{
|
|
|
|
m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
|
|
|
|
}
|
|
|
|
else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
|
|
|
|
{
|
|
|
|
m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box );
|
|
|
|
}
|
2006-02-26 10:55:20 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_actor_transform_valid = false;
|
2006-05-14 00:11:46 +02:00
|
|
|
|
|
|
|
if( m_player )
|
|
|
|
{
|
|
|
|
// Make sure the actor has the right player colour
|
|
|
|
m_actor->SetPlayerID( m_player->GetPlayerID() );
|
|
|
|
}
|
2006-07-10 01:12:37 +02:00
|
|
|
|
|
|
|
// Re-enter all our auras so they can take into account our new traits
|
2007-01-25 08:00:31 +01:00
|
|
|
ExitAuras();
|
2006-07-12 21:31:27 +02:00
|
|
|
|
|
|
|
// Resize sectors array
|
|
|
|
m_sectorValues.resize(m_base->m_sectorDivs);
|
|
|
|
for ( int i=0; i<m_base->m_sectorDivs; ++i )
|
|
|
|
m_sectorValues[i] = false;
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
2007-01-25 08:00:31 +01:00
|
|
|
|
2006-08-25 08:04:33 +02:00
|
|
|
void CEntity::initAuraData()
|
|
|
|
{
|
|
|
|
if ( m_auras.empty() )
|
|
|
|
return;
|
|
|
|
m_unsnappedPoints.resize(m_auras.size());
|
|
|
|
size_t i=0;
|
|
|
|
for ( AuraTable::iterator it=m_auras.begin(); it!=m_auras.end(); ++it, ++i )
|
|
|
|
{
|
2006-10-08 19:39:46 +02:00
|
|
|
m_unsnappedPoints[i].resize(AURA_CIRCLE_POINTS);
|
2006-08-25 08:04:33 +02:00
|
|
|
float radius = it->second->m_radius;
|
2004-05-22 01:46:16 +02:00
|
|
|
|
2006-10-08 19:39:46 +02:00
|
|
|
for ( int j=0; j<AURA_CIRCLE_POINTS; ++j )
|
2006-08-25 08:04:33 +02:00
|
|
|
{
|
2006-10-08 19:39:46 +02:00
|
|
|
float val = j * 2*PI / (float)AURA_CIRCLE_POINTS;
|
2006-08-25 08:04:33 +02:00
|
|
|
m_unsnappedPoints[i][j] = CVector2D( cosf(val)*radius,
|
|
|
|
sinf(val)*radius );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
void CEntity::kill(bool keepActor)
|
|
|
|
{
|
|
|
|
if( entf_get( ENTF_DESTROYED ) )
|
|
|
|
{
|
|
|
|
return; // We were already killed this frame
|
|
|
|
}
|
2006-07-20 16:37:58 +02:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
g_FormationManager.RemoveUnit(this);
|
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_set(ENTF_DESTROY_NOTIFIERS);
|
2006-05-04 06:14:48 +02:00
|
|
|
for ( size_t i=0; i<m_listeners.size(); i++ )
|
|
|
|
m_listeners[i].m_sender->DestroyNotifier( this );
|
2007-01-25 08:00:31 +01:00
|
|
|
m_listeners.clear();
|
2006-04-09 00:34:54 +02:00
|
|
|
DestroyAllNotifiers();
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
for( AuraTable::iterator it = m_auras.begin(); it != m_auras.end(); it++ )
|
|
|
|
{
|
|
|
|
it->second->RemoveAll();
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
m_auras.clear();
|
|
|
|
|
|
|
|
ExitAuras();
|
|
|
|
|
|
|
|
clearOrders();
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
SAFE_DELETE(m_bounds);
|
2004-07-20 21:30:35 +02:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_extant = false;
|
2005-12-11 03:09:11 +01:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
updateCollisionPatch();
|
2004-11-11 08:09:32 +01:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
g_Selection.removeAll( me );
|
|
|
|
|
2007-02-08 06:38:53 +01:00
|
|
|
entf_set(ENTF_DESTROYED);
|
2007-02-10 04:09:52 +01:00
|
|
|
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
|
2007-02-08 06:38:53 +01:00
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
// If we have a death animation and want to keep the actor, play that animation
|
|
|
|
if( keepActor && m_actor &&
|
2007-02-10 04:09:52 +01:00
|
|
|
m_actor->HasAnimation( "death" ) )
|
2007-01-25 08:00:31 +01:00
|
|
|
{
|
|
|
|
// Prevent "wiggling" as we try to interpolate between here and our death position (if we were moving)
|
|
|
|
m_graphics_position = m_position;
|
|
|
|
m_position_previous = m_position;
|
|
|
|
m_graphics_orientation = m_orientation;
|
|
|
|
m_orientation_previous = m_orientation;
|
2007-02-10 18:39:20 +01:00
|
|
|
|
2007-02-08 06:38:53 +01:00
|
|
|
snapToGround();
|
2007-02-10 18:39:20 +01:00
|
|
|
|
|
|
|
// Conform to the ground
|
|
|
|
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace(this);
|
|
|
|
m_orientation.X = clamp( targetXZ.x, -1.0f, 1.0f );
|
|
|
|
m_orientation.Z = clamp( targetXZ.y, -1.0f, 1.0f );
|
|
|
|
m_orientation_unclamped.x = targetXZ.x;
|
|
|
|
m_orientation_unclamped.y = targetXZ.y;
|
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
updateActorTransforms();
|
2007-02-08 06:38:53 +01:00
|
|
|
m_actor_transform_valid = true;
|
2007-01-25 08:00:31 +01:00
|
|
|
|
|
|
|
// Play death animation and keep the actor in the game in a dead state
|
|
|
|
// (TODO: remove the actor after some time through some kind of fading mechanism)
|
2007-02-10 04:09:52 +01:00
|
|
|
m_actor->SetAnimationState( "death", true );
|
2007-01-25 08:00:31 +01:00
|
|
|
}
|
|
|
|
else
|
2006-07-20 16:37:58 +02:00
|
|
|
{
|
2007-02-10 04:09:52 +01:00
|
|
|
g_Game->GetWorld()->GetUnitManager().DeleteUnit( m_actor );
|
2006-07-20 16:37:58 +02:00
|
|
|
m_actor = NULL;
|
2007-01-25 08:00:31 +01:00
|
|
|
|
2007-02-08 06:38:53 +01:00
|
|
|
me = HEntity(); // Will deallocate the entity, assuming nobody else has a reference to it
|
|
|
|
}
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
2005-01-23 23:38:13 +01:00
|
|
|
void CEntity::SetPlayer(CPlayer *pPlayer)
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_player = pPlayer;
|
2005-01-23 23:38:13 +01:00
|
|
|
|
2006-09-02 23:20:25 +02:00
|
|
|
// This should usually be called CUnit::SetPlayerID, so we don't need to
|
|
|
|
// update the actor here.
|
2006-07-10 01:12:37 +02:00
|
|
|
|
|
|
|
// If we're a territory centre, change the territory's owner
|
|
|
|
if( m_associatedTerritory )
|
|
|
|
m_associatedTerritory->owner = pPlayer;
|
2005-01-23 23:38:13 +01:00
|
|
|
}
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
void CEntity::updateActorTransforms()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CMatrix3D m;
|
2006-05-04 06:14:48 +02:00
|
|
|
CMatrix3D mXZ;
|
|
|
|
float Cos = cosf( m_graphics_orientation.Y );
|
|
|
|
float Sin = sinf( m_graphics_orientation.Y );
|
2006-04-22 07:52:23 +02:00
|
|
|
|
|
|
|
m._11=-Cos; m._12=0.0f; m._13=-Sin; m._14=0.0f;
|
|
|
|
m._21=0.0f; m._22=1.0f; m._23=0.0f; m._24=0.0f;
|
|
|
|
m._31=Sin; m._32=0.0f; m._33=-Cos; m._34=0.0f;
|
|
|
|
m._41=0.0f; m._42=0.0f; m._43=0.0f; m._44=1.0f;
|
2006-07-20 16:37:58 +02:00
|
|
|
|
2006-05-04 06:14:48 +02:00
|
|
|
mXZ.SetXRotation( m_graphics_orientation.X );
|
|
|
|
mXZ.RotateZ( m_graphics_orientation.Z );
|
|
|
|
mXZ = m*mXZ;
|
|
|
|
mXZ.Translate(m_graphics_position);
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_actor )
|
|
|
|
m_actor->GetModel()->SetTransform( mXZ );
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::snapToGround()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_graphics_position.Y = getAnchorLevel( m_graphics_position.X, m_graphics_position.Z );
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2006-09-16 23:30:23 +02:00
|
|
|
void CEntity::updateXZOrientation()
|
|
|
|
{
|
|
|
|
// Make sure m_ahead is correct
|
|
|
|
m_ahead.x = sin( m_orientation.Y );
|
|
|
|
m_ahead.y = cos( m_orientation.Y );
|
|
|
|
|
|
|
|
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace(this);
|
|
|
|
m_orientation.X = clamp( targetXZ.x, -m_base->m_anchorConformX, m_base->m_anchorConformX );
|
|
|
|
m_orientation.Z = clamp( targetXZ.y, -m_base->m_anchorConformZ, m_base->m_anchorConformZ );
|
|
|
|
m_orientation_unclamped.x = targetXZ.x;
|
|
|
|
m_orientation_unclamped.y = targetXZ.y;
|
|
|
|
}
|
2006-07-24 03:33:26 +02:00
|
|
|
|
2005-05-01 21:09:13 +02:00
|
|
|
jsval CEntity::getClassSet()
|
|
|
|
{
|
2006-07-24 03:33:26 +02:00
|
|
|
CStrW result = m_classes.getMemberList();
|
2006-07-20 16:37:58 +02:00
|
|
|
return( ToJSVal( result ) );
|
2005-05-01 21:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::setClassSet( jsval value )
|
|
|
|
{
|
2006-07-24 03:33:26 +02:00
|
|
|
CStr memberCmdList = ToPrimitive<CStrW>( value );
|
|
|
|
m_classes.setFromMemberList(memberCmdList);
|
2006-07-20 16:37:58 +02:00
|
|
|
|
|
|
|
rebuildClassSet();
|
2005-05-01 21:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::rebuildClassSet()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_classes.Rebuild();
|
|
|
|
InheritorsList::iterator it;
|
|
|
|
for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ )
|
|
|
|
(*it)->rebuildClassSet();
|
2005-05-01 21:09:13 +02:00
|
|
|
}
|
|
|
|
|
2004-07-27 23:00:53 +02:00
|
|
|
void CEntity::update( size_t timestep )
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
2006-07-30 01:58:33 +02:00
|
|
|
if( !m_extant ) return;
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_position_previous = m_position;
|
|
|
|
m_orientation_previous = m_orientation;
|
2007-01-24 21:17:28 +01:00
|
|
|
|
2006-07-24 03:33:26 +02:00
|
|
|
CalculateRegen( timestep );
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
if ( entf_get(ENTF_TRIGGER_RUN) )
|
2006-01-21 12:17:15 +01:00
|
|
|
m_frameCheck++;
|
2006-04-21 05:06:57 +02:00
|
|
|
|
2006-01-16 11:56:47 +01:00
|
|
|
if ( m_frameCheck != 0 )
|
|
|
|
{
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_set(ENTF_SHOULD_RUN);
|
|
|
|
entf_clear(ENTF_TRIGGER_RUN);
|
2006-01-16 11:56:47 +01:00
|
|
|
m_frameCheck = 0;
|
|
|
|
}
|
|
|
|
|
2006-02-22 23:45:16 +01:00
|
|
|
m_productionQueue->Update( timestep );
|
|
|
|
|
2006-01-16 11:56:47 +01:00
|
|
|
// Note: aura processing is done before state processing because the state
|
2006-07-20 16:37:58 +02:00
|
|
|
// processing code is filled with all kinds of returns
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
PROFILE_START( "aura processing" );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
for( AuraTable::iterator it = m_auras.begin(); it != m_auras.end(); it++ )
|
|
|
|
{
|
|
|
|
it->second->Update( timestep );
|
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
PROFILE_END( "aura processing" );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
// The process[...] functions return 'true' if the order at the top of the stack
|
|
|
|
// still needs to be (re-)evaluated; else 'false' to terminate the processing of
|
|
|
|
// this entity in this timestep.
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
PROFILE_START( "state processing" );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-12 18:18:31 +02:00
|
|
|
if( entf_get(ENTF_IS_RUNNING) )
|
2006-05-16 06:41:37 +02:00
|
|
|
{
|
|
|
|
m_lastRunTime = g_Game->GetTime();
|
|
|
|
}
|
|
|
|
|
2006-09-09 02:00:23 +02:00
|
|
|
if( m_orderQueue.empty() )
|
|
|
|
{
|
|
|
|
// We are idle. Tell our stance in case it wants us to do something.
|
|
|
|
PROFILE( "unit ai" );
|
|
|
|
m_stance->onIdle();
|
|
|
|
}
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
while( !m_orderQueue.empty() )
|
2006-05-16 06:41:37 +02:00
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CEntityOrder* current = &m_orderQueue.front();
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( current->m_type != m_lastState )
|
|
|
|
{
|
|
|
|
entf_set(ENTF_TRANSITION);
|
|
|
|
m_fsm_cyclepos = NOT_IN_CYCLE;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
PROFILE( "state transition / order" );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
CEntity* target = NULL;
|
2006-12-21 15:57:13 +01:00
|
|
|
if( current->m_target_entity )
|
|
|
|
target = &( *( current->m_target_entity ) );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-12-21 15:57:13 +01:00
|
|
|
CVector3D worldPosition = (CVector3D)current->m_target_location;
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
CEventOrderTransition evt( m_lastState, current->m_type, target, worldPosition );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( !DispatchEvent( &evt ) )
|
|
|
|
{
|
|
|
|
m_orderQueue.pop_front();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if( target )
|
|
|
|
{
|
2006-12-21 15:57:13 +01:00
|
|
|
current->m_target_location = worldPosition;
|
|
|
|
current->m_target_entity = target->me;
|
2006-07-20 16:37:58 +02:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_lastState = current->m_type;
|
|
|
|
}
|
|
|
|
else
|
2005-12-29 10:12:54 +01:00
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
entf_clear(ENTF_TRANSITION);
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
switch( current->m_type )
|
|
|
|
{
|
|
|
|
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
|
|
|
case CEntityOrder::ORDER_GOTO_COLLISION:
|
|
|
|
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
2005-12-29 10:12:54 +01:00
|
|
|
if( processGotoNoPathing( current, timestep ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_GENERIC:
|
2005-12-29 10:12:54 +01:00
|
|
|
if( processGeneric( current, timestep ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-05-04 09:40:31 +02:00
|
|
|
case CEntityOrder::ORDER_START_CONSTRUCTION:
|
|
|
|
{
|
2006-12-21 15:57:13 +01:00
|
|
|
CEventStartConstruction evt( current->m_new_obj );
|
2006-05-04 09:40:31 +02:00
|
|
|
m_orderQueue.pop_front();
|
|
|
|
DispatchEvent( &evt );
|
|
|
|
}
|
|
|
|
break;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_PRODUCE:
|
2006-02-22 23:45:16 +01:00
|
|
|
processProduce( current );
|
|
|
|
m_orderQueue.pop_front();
|
|
|
|
break;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_GENERIC_NOPATHING:
|
2005-12-29 10:12:54 +01:00
|
|
|
if( processGenericNoPathing( current, timestep ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-04-09 02:36:52 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO_WAYPOINT:
|
2006-04-11 00:05:21 +02:00
|
|
|
if ( processGotoWaypoint( current, timestep, false ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
|
|
|
case CEntityOrder::ORDER_GOTO_WAYPOINT_CONTACT:
|
|
|
|
if ( processGotoWaypoint( current, timestep, true ) )
|
2006-04-09 02:36:52 +02:00
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO:
|
2006-01-16 11:56:47 +01:00
|
|
|
case CEntityOrder::ORDER_RUN:
|
2005-12-29 10:12:54 +01:00
|
|
|
if( processGoto( current, timestep ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_PATROL:
|
2005-12-29 10:12:54 +01:00
|
|
|
if( processPatrol( current, timestep ) )
|
|
|
|
break;
|
|
|
|
updateCollisionPatch();
|
|
|
|
return;
|
2006-07-20 16:37:58 +02:00
|
|
|
case CEntityOrder::ORDER_PATH_END_MARKER:
|
2005-12-29 10:12:54 +01:00
|
|
|
m_orderQueue.pop_front();
|
|
|
|
break;
|
2006-07-20 16:37:58 +02:00
|
|
|
default:
|
2006-05-14 00:11:46 +02:00
|
|
|
debug_warn( "Invalid entity order" );
|
2006-02-22 23:45:16 +01:00
|
|
|
}
|
2006-07-20 16:37:58 +02:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-05-13 06:07:42 +02:00
|
|
|
if( m_orderQueue.empty() )
|
|
|
|
{
|
|
|
|
// If we have no orders, stop running
|
2006-07-12 18:18:31 +02:00
|
|
|
entf_clear(ENTF_IS_RUNNING);
|
|
|
|
entf_clear(ENTF_SHOULD_RUN);
|
2006-05-13 06:07:42 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
PROFILE_END( "state processing" );
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-05-16 06:41:37 +02:00
|
|
|
// If we get to here, it means we're idle or dead (no orders); update the animation
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_actor )
|
|
|
|
{
|
|
|
|
PROFILE( "animation updates" );
|
|
|
|
if( m_extant )
|
|
|
|
{
|
|
|
|
if( ( m_lastState != -1 ) || !m_actor->GetModel()->GetAnimation() )
|
2006-03-17 04:59:49 +01:00
|
|
|
{
|
2007-02-10 04:09:52 +01:00
|
|
|
m_actor->SetAnimationState( "idle" );
|
2006-03-17 04:59:49 +01:00
|
|
|
}
|
2006-07-20 16:37:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_lastState != -1 )
|
|
|
|
{
|
|
|
|
PROFILE( "state transition event" );
|
2007-01-25 08:00:31 +01:00
|
|
|
CVector3D vec(0, 0, 0);
|
|
|
|
CEventOrderTransition evt( m_lastState, -1, 0, vec );
|
2006-07-20 16:37:58 +02:00
|
|
|
DispatchEvent( &evt );
|
|
|
|
|
|
|
|
m_lastState = -1;
|
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2005-12-16 06:35:26 +01:00
|
|
|
void CEntity::updateCollisionPatch()
|
|
|
|
{
|
2006-09-26 03:44:20 +02:00
|
|
|
std::vector<CEntity*>* newPatch = g_EntityManager.getCollisionPatch( this );
|
2006-07-20 16:37:58 +02:00
|
|
|
if( newPatch != m_collisionPatch )
|
|
|
|
{
|
|
|
|
if( m_collisionPatch )
|
|
|
|
{
|
|
|
|
// remove ourselves from old patch
|
2006-09-26 03:44:20 +02:00
|
|
|
std::vector<CEntity*>& old = *m_collisionPatch;
|
2006-07-20 16:37:58 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-25 08:00:31 +01:00
|
|
|
if( newPatch )
|
2006-07-20 16:37:58 +02:00
|
|
|
{
|
|
|
|
// add ourselves to new patch
|
|
|
|
newPatch->push_back( this );
|
|
|
|
m_collisionPatch = newPatch;
|
|
|
|
}
|
|
|
|
}
|
2005-12-16 06:35:26 +01:00
|
|
|
}
|
|
|
|
|
2005-05-27 02:38:30 +02:00
|
|
|
#if AURA_TEST
|
|
|
|
void CEntity::UpdateAuras( size_t timestep_millis )
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
std::vector<SAura>::iterator it_a;
|
|
|
|
for( it_a = m_Auras.begin(); it_a != m_Auras.end(); it_a++ )
|
|
|
|
{
|
|
|
|
SAuraData& d = it_a->m_Data;
|
|
|
|
std::set<CEntity*>
|
|
|
|
& inRange = GetEntitiesWithinRange( m_position, d.m_Radius );
|
|
|
|
|
|
|
|
std::vector<CEntity*>::iterator it1 = inRange.begin();
|
|
|
|
std::vector<SAuraInstance>::iterator it2 = it_a->m_Influenced.begin();
|
|
|
|
|
|
|
|
while( WORLD_IS_ROUND )
|
|
|
|
{
|
|
|
|
if( it1 == inRange.end() )
|
|
|
|
{
|
|
|
|
// No more in range => anything else in the influenced set must have gone
|
|
|
|
// out of range.
|
|
|
|
for( ; it2 != it_a->m_Influenced.end(); it2++ )
|
|
|
|
UpdateAuras_LeaveRange( *it_a, it2->GetEntity() );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( it2 == it_a->m_Influenced.end() )
|
|
|
|
{
|
|
|
|
// Everything else in the in-range set has only just come into range
|
|
|
|
for( ; it1 != inRange.end(); it1++ )
|
|
|
|
UpdateAuras_EnterRange( *it_a, *it );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
CEntity* e1 = *it1, e2 = it2->GetEntity();
|
|
|
|
if( e1 < e2 )
|
|
|
|
{
|
|
|
|
// A new entity e1 has just come into range.
|
|
|
|
// Check to see if it can be affected by the aura.
|
|
|
|
UpdateAuras_EnterRange( *it_a, e1 );
|
|
|
|
++it1;
|
|
|
|
}
|
|
|
|
else if( e1 == e2 )
|
|
|
|
{
|
|
|
|
// The entity e1/e2 was previously in range, and still is.
|
|
|
|
UpdateAuras_Normal( *it_a, e1 );
|
|
|
|
++it1;
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// The entity e2 was previously in range, but is no longer.
|
|
|
|
UpdateAuras_LeaveRange( *it_a, e2 );
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-05-27 02:38:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateAuras_EnterRange( SAura& aura, CEntity* e )
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
if( aura.m_Recharge )
|
|
|
|
return( false );
|
|
|
|
// Check to see if the entity is eligable
|
|
|
|
if( !UpdateAuras_IsEligable( aura.m_Data, e ) )
|
|
|
|
return; // Do nothing.
|
|
|
|
|
|
|
|
SAuraInstance ai;
|
|
|
|
ai.m_Influenced = e;
|
|
|
|
ai.m_EnteredRange = ai.m_LastInRange = 0;
|
|
|
|
ai.m_Applied = -1;
|
|
|
|
|
|
|
|
// If there's no timer, apply the effect now.
|
|
|
|
if( aura.m_Data.m_Time == 0 )
|
|
|
|
{
|
|
|
|
e->ApplyAuraEffect( aura.m_Data );
|
|
|
|
ai.m_Applied = 0;
|
|
|
|
aura.m_Recharge = aura.m_Data.m_Cooldown;
|
|
|
|
}
|
|
|
|
|
|
|
|
aura.m_Influenced.push_back( ai );
|
2005-05-27 02:38:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateAuras_Normal( SAura& aura, CEntity* e )
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
// Is the entity no longer eligable?
|
|
|
|
if( !UpdateAuras_IsEligable( aura.m_Data, e ) )
|
|
|
|
{
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UpdateAuras_IsEligable( SAuraData& aura, CEntity* e )
|
|
|
|
{
|
|
|
|
if( e == this )
|
|
|
|
{
|
|
|
|
if( !( aura.m_Allegiance & SAuraData::SELF ) )
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
else if( e->m_player == GetGaiaPlayer() )
|
|
|
|
{
|
|
|
|
if( !( aura.m_Allegiance & SAuraData::GAIA ) )
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
else if( e->m_player == m_player )
|
|
|
|
{
|
|
|
|
if( !( aura.m_Allegiance & SAuraData::PLAYER ) )
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
// TODO: Allied players
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !( aura.m_Allegiance & SAuraData::ENEMY ) )
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
if( e->m_hp > e->m_hp_max * aura.m_Hitpoints )
|
|
|
|
return( false );
|
|
|
|
return( true );
|
|
|
|
}
|
2007-01-24 21:17:28 +01:00
|
|
|
}
|
2004-07-20 21:30:35 +02:00
|
|
|
#endif
|
|
|
|
|
2006-06-10 05:05:16 +02:00
|
|
|
bool CEntity::Initialize()
|
2005-12-29 10:12:54 +01:00
|
|
|
{
|
2006-07-19 01:59:48 +02:00
|
|
|
// 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();
|
2006-07-21 02:05:56 +02:00
|
|
|
for( size_t i=0; i<techs.size(); i++ )
|
2006-07-19 01:59:48 +02:00
|
|
|
{
|
|
|
|
techs[i]->apply( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dispatch the initialize script event
|
2005-12-29 10:12:54 +01:00
|
|
|
CEventInitialize evt;
|
2006-06-10 05:05:16 +02:00
|
|
|
if( !DispatchEvent( &evt ) )
|
|
|
|
{
|
2006-10-08 19:39:46 +02:00
|
|
|
//debug_printf("start construction failed, killing self\n");
|
2006-06-10 05:05:16 +02:00
|
|
|
kill();
|
|
|
|
return false;
|
|
|
|
}
|
2006-10-08 19:39:46 +02:00
|
|
|
|
|
|
|
if( g_EntityManager.m_screenshotMode )
|
|
|
|
{
|
|
|
|
// Stay in Hold stance no matter what the init script wanted us to be
|
|
|
|
m_stanceName = "hold";
|
|
|
|
stanceChanged();
|
|
|
|
}
|
|
|
|
|
2006-06-10 05:05:16 +02:00
|
|
|
return true;
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2007-01-24 21:17:28 +01:00
|
|
|
/*
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::Tick()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CEventTick evt;
|
|
|
|
DispatchEvent( &evt );
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2007-01-24 21:17:28 +01:00
|
|
|
*/
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::clearOrders()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
if ( m_orderQueue.empty() )
|
2006-04-09 00:34:54 +02:00
|
|
|
return;
|
|
|
|
CIdleEvent evt( m_orderQueue.front(), m_currentNotification );
|
|
|
|
DispatchEvent(&evt);
|
|
|
|
m_orderQueue.clear();
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2006-04-09 00:34:54 +02:00
|
|
|
void CEntity::popOrder()
|
|
|
|
{
|
|
|
|
if ( m_orderQueue.empty() )
|
|
|
|
return;
|
|
|
|
CIdleEvent evt( m_orderQueue.front(), m_currentNotification );
|
|
|
|
DispatchEvent(&evt);
|
2005-12-29 10:12:54 +01:00
|
|
|
|
2006-04-09 00:34:54 +02:00
|
|
|
m_orderQueue.pop_front();
|
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::pushOrder( CEntityOrder& order )
|
|
|
|
{
|
2006-12-21 15:57:13 +01:00
|
|
|
CEventPrepareOrder evt( order.m_target_entity, order.m_type, order.m_action, order.m_produce_name );
|
2006-02-13 04:32:15 +01:00
|
|
|
if( DispatchEvent(&evt) )
|
2006-07-20 16:37:58 +02:00
|
|
|
{
|
2006-02-22 23:45:16 +01:00
|
|
|
m_orderQueue.push_back( order );
|
2006-04-21 05:06:57 +02:00
|
|
|
if(evt.m_notifyType != CEntityListener::NOTIFY_NONE)
|
2006-02-22 23:45:16 +01:00
|
|
|
{
|
|
|
|
CheckListeners( evt.m_notifyType, evt.m_notifySource );
|
|
|
|
}
|
2006-07-20 16:37:58 +02:00
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
|
|
|
|
2006-02-13 04:32:15 +01:00
|
|
|
void CEntity::DispatchNotification( CEntityOrder order, int type )
|
2005-12-29 05:56:15 +01:00
|
|
|
{
|
2006-01-08 09:25:11 +01:00
|
|
|
CEventNotification evt( order, type );
|
|
|
|
DispatchEvent( &evt );
|
|
|
|
}
|
2006-04-14 05:14:43 +02:00
|
|
|
|
|
|
|
struct isListenerSender
|
|
|
|
{
|
|
|
|
CEntity* sender;
|
|
|
|
isListenerSender(CEntity* sender) : sender(sender) {}
|
|
|
|
bool operator()(CEntityListener& listener)
|
|
|
|
{
|
|
|
|
return listener.m_sender == sender;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-04-09 00:34:54 +02:00
|
|
|
int CEntity::DestroyNotifier( CEntity* target )
|
2006-02-13 04:32:15 +01:00
|
|
|
{
|
2006-04-09 00:34:54 +02:00
|
|
|
//Stop listening
|
2006-04-14 05:14:43 +02:00
|
|
|
// (Don't just loop and use 'erase', because modifying the deque while
|
|
|
|
// looping over it is a bit dangerous)
|
|
|
|
std::deque<CEntityListener>::iterator newEnd = std::remove_if(
|
|
|
|
target->m_listeners.begin(), target->m_listeners.end(),
|
|
|
|
isListenerSender(this));
|
|
|
|
target->m_listeners.erase(newEnd, target->m_listeners.end());
|
|
|
|
|
2006-04-09 00:34:54 +02:00
|
|
|
//Get rid of our copy
|
2006-04-14 05:14:43 +02:00
|
|
|
std::vector<CEntity*>::iterator newEnd2 = std::remove_if(
|
|
|
|
m_notifiers.begin(), m_notifiers.end(),
|
|
|
|
bind2nd(std::equal_to<CEntity*>(), target));
|
2006-10-10 07:21:41 +02:00
|
|
|
int removed = m_notifiers.end() - newEnd2;
|
|
|
|
//m_notifiers.erase(newEnd2, m_notifiers.end());
|
|
|
|
m_notifiers.resize(m_notifiers.size() - removed);
|
2006-04-09 00:34:54 +02:00
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
void CEntity::DestroyAllNotifiers()
|
|
|
|
{
|
2006-07-12 18:18:31 +02:00
|
|
|
debug_assert(entf_get(ENTF_DESTROY_NOTIFIERS));
|
2006-04-09 00:34:54 +02:00
|
|
|
//Make them stop listening to us
|
2006-04-14 05:14:43 +02:00
|
|
|
while ( ! m_notifiers.empty() )
|
2006-10-10 07:21:41 +02:00
|
|
|
DestroyNotifier( m_notifiers[m_notifiers.size()-1] );
|
2006-02-13 04:32:15 +01:00
|
|
|
}
|
2006-03-31 05:30:34 +02:00
|
|
|
CEntityFormation* CEntity::GetFormation()
|
|
|
|
{
|
|
|
|
if ( m_formation < 0 )
|
|
|
|
return NULL;
|
|
|
|
return g_FormationManager.GetFormation(m_formation);
|
|
|
|
}
|
|
|
|
void CEntity::DispatchFormationEvent( int type )
|
|
|
|
{
|
|
|
|
CFormationEvent evt( type );
|
|
|
|
DispatchEvent( &evt );
|
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::repath()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CVector2D destination;
|
2006-09-09 02:00:23 +02:00
|
|
|
CEntityOrder::EOrderSource orderSource = CEntityOrder::SOURCE_PLAYER;
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_orderQueue.empty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
while( !m_orderQueue.empty() &&
|
|
|
|
( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
|
|
|
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|
|
|
|
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
|
|
|
|
{
|
2006-12-21 15:57:13 +01:00
|
|
|
destination = m_orderQueue.front().m_target_location;
|
2006-09-09 02:00:23 +02:00
|
|
|
orderSource = m_orderQueue.front().m_source;
|
2006-07-20 16:37:58 +02:00
|
|
|
m_orderQueue.pop_front();
|
|
|
|
}
|
2006-09-09 02:00:23 +02:00
|
|
|
g_Pathfinder.requestPath( me, destination, orderSource );
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::reorient()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_orientation = m_graphics_orientation;
|
2006-05-04 06:14:48 +02:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_ahead.x = sin( m_orientation.Y );
|
|
|
|
m_ahead.y = cos( m_orientation.Y );
|
|
|
|
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
|
|
|
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
|
|
|
updateActorTransforms();
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::teleport()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_position = m_graphics_position;
|
|
|
|
m_bounds->setPosition( m_position.X, m_position.Z );
|
2006-09-09 02:00:23 +02:00
|
|
|
updateActorTransforms();
|
2006-07-20 16:37:58 +02:00
|
|
|
updateCollisionPatch();
|
|
|
|
repath();
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2006-09-09 02:00:23 +02:00
|
|
|
void CEntity::stanceChanged()
|
|
|
|
{
|
|
|
|
delete m_stance;
|
|
|
|
m_stance = 0;
|
|
|
|
|
|
|
|
if( m_stanceName == "aggress" )
|
|
|
|
{
|
|
|
|
m_stance = new CAggressStance( this );
|
|
|
|
}
|
|
|
|
else if( m_stanceName == "defend" )
|
|
|
|
{
|
|
|
|
m_stance = new CDefendStance( this );
|
|
|
|
}
|
|
|
|
else if( m_stanceName == "stand" )
|
|
|
|
{
|
|
|
|
m_stance = new CStandStance( this );
|
|
|
|
}
|
2006-09-16 23:30:23 +02:00
|
|
|
else // m_stanceName == "hold" or undefined stance
|
2006-09-09 02:00:23 +02:00
|
|
|
{
|
2006-09-16 23:30:23 +02:00
|
|
|
m_stance = new CHoldStance( this );
|
2006-09-09 02:00:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::checkSelection()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
if( m_selected )
|
|
|
|
{
|
|
|
|
if( !g_Selection.isSelected( me ) )
|
|
|
|
g_Selection.addSelection( me );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( g_Selection.isSelected( me ) )
|
|
|
|
g_Selection.removeSelection( me );
|
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::checkGroup()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
g_Selection.changeGroup( me, -1 ); // Ungroup
|
|
|
|
if( ( m_grouped >= 0 ) && ( m_grouped < MAX_GROUPS ) )
|
|
|
|
g_Selection.changeGroup( me, m_grouped );
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::interpolate( float relativeoffset )
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CVector3D old_graphics_position = m_graphics_position;
|
|
|
|
CVector3D old_graphics_orientation = m_graphics_orientation;
|
2006-05-04 06:14:48 +02:00
|
|
|
|
2007-01-24 21:17:28 +01:00
|
|
|
relativeoffset = clamp( relativeoffset, 0.f, 1.f );
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_graphics_position = Interpolate<CVector3D>( m_position_previous, m_position, relativeoffset );
|
2005-12-29 10:12:54 +01:00
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
// Avoid wraparound glitches for interpolating angles.
|
2006-05-29 05:28:54 +02:00
|
|
|
|
|
|
|
m_orientation.X = fmodf(m_orientation.X, 2*PI); // (ensure the following loops can't take forever)
|
|
|
|
m_orientation.Y = fmodf(m_orientation.Y, 2*PI);
|
|
|
|
m_orientation.Z = fmodf(m_orientation.Z, 2*PI);
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
while( m_orientation.Y < m_orientation_previous.Y - PI )
|
|
|
|
m_orientation_previous.Y -= 2 * PI;
|
|
|
|
while( m_orientation.Y > m_orientation_previous.Y + PI )
|
|
|
|
m_orientation_previous.Y += 2 * PI;
|
2006-05-04 06:14:48 +02:00
|
|
|
|
|
|
|
while( m_orientation.X < m_orientation_previous.X - PI )
|
2006-07-20 16:37:58 +02:00
|
|
|
m_orientation_previous.X -= 2 * PI;
|
|
|
|
while( m_orientation.X > m_orientation_previous.X + PI )
|
|
|
|
m_orientation_previous.X += 2 * PI;
|
2005-12-29 10:12:54 +01:00
|
|
|
|
2006-05-04 06:14:48 +02:00
|
|
|
while( m_orientation.Z < m_orientation_previous.Z - PI )
|
2006-07-20 16:37:58 +02:00
|
|
|
m_orientation_previous.Z -= 2 * PI;
|
|
|
|
while( m_orientation.Z > m_orientation_previous.Z + PI )
|
|
|
|
m_orientation_previous.Z += 2 * PI;
|
|
|
|
|
2006-09-16 23:30:23 +02:00
|
|
|
updateXZOrientation();
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
m_graphics_orientation = Interpolate<CVector3D>( m_orientation_previous, m_orientation, relativeoffset );
|
|
|
|
|
|
|
|
// Mark the actor transform data as invalid if the entity has moved since
|
|
|
|
// the last call to 'interpolate'.
|
|
|
|
// position.Y is ignored because we can't determine the new value without
|
|
|
|
// calling snapToGround, which is slow. TODO: This may need to be adjusted to
|
|
|
|
// handle flying units or moving terrain.
|
|
|
|
if( m_graphics_orientation != old_graphics_orientation ||
|
|
|
|
m_graphics_position.X != old_graphics_position.X ||
|
|
|
|
m_graphics_position.Z != old_graphics_position.Z
|
2006-04-22 07:52:23 +02:00
|
|
|
)
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_actor_transform_valid = false;
|
|
|
|
}
|
|
|
|
// Update the actor transform data when necessary.
|
|
|
|
if( !m_actor_transform_valid )
|
|
|
|
{
|
|
|
|
snapToGround();
|
|
|
|
updateActorTransforms();
|
|
|
|
m_actor_transform_valid = true;
|
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2005-12-18 08:33:16 +01:00
|
|
|
|
2005-12-29 10:12:54 +01:00
|
|
|
void CEntity::invalidateActor()
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
m_actor_transform_valid = false;
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float CEntity::getAnchorLevel( float x, float z )
|
|
|
|
{
|
2006-07-20 16:37:58 +02:00
|
|
|
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
|
|
|
|
float groundLevel = pTerrain->getExactGroundLevel( x, z );
|
|
|
|
if( m_base->m_anchorType==L"Ground" )
|
|
|
|
{
|
|
|
|
return groundLevel;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-09-26 03:44:20 +02:00
|
|
|
return std::max( groundLevel, g_Renderer.GetWaterManager()->m_WaterHeight );
|
2006-07-20 16:37:58 +02:00
|
|
|
}
|
2005-12-29 10:12:54 +01:00
|
|
|
}
|
2006-09-09 02:00:23 +02:00
|
|
|
|
2006-05-04 06:14:48 +02:00
|
|
|
int CEntity::findSector( int divs, float angle, float maxAngle, bool negative )
|
|
|
|
{
|
|
|
|
float step=maxAngle/divs;
|
|
|
|
if ( negative )
|
|
|
|
{
|
|
|
|
float tracker;
|
|
|
|
int i=1, sectorRemainder;
|
|
|
|
for ( tracker=-maxAngle/2.0f; tracker+step<0.0f; tracker+=step, ++i )
|
|
|
|
{
|
|
|
|
if ( angle > tracker && angle <= tracker+step )
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
sectorRemainder = i;
|
|
|
|
i=divs;
|
|
|
|
for ( tracker=maxAngle/2.0f; tracker-step>0.0f; tracker-=step, --i )
|
|
|
|
{
|
|
|
|
if ( angle < tracker && angle >= tracker-step )
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return sectorRemainder;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-07-06 05:17:44 +02:00
|
|
|
int i=1;
|
2006-05-04 06:14:48 +02:00
|
|
|
for ( float tracker=0.0f; tracker<maxAngle; tracker+=step, ++i )
|
|
|
|
{
|
|
|
|
if ( angle > tracker && angle <= tracker+step )
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debug_warn("CEntity::findSector() - invalid parameters passed.");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-07-24 03:33:26 +02:00
|
|
|
|
|
|
|
static inline float regen(float cur, float limit, float timestep, float regen_rate)
|
2006-01-16 11:56:47 +01:00
|
|
|
{
|
2006-07-24 03:33:26 +02:00
|
|
|
if(regen_rate <= 0)
|
|
|
|
return cur;
|
|
|
|
return std::min(limit, cur + timestep / 1000.0f * regen_rate * limit );
|
2006-01-16 11:56:47 +01:00
|
|
|
}
|
2006-01-20 22:38:58 +01:00
|
|
|
|
2006-07-24 03:33:26 +02:00
|
|
|
static inline float decay(float cur, float limit, float timestep, float decay_rate)
|
2006-01-21 12:17:15 +01:00
|
|
|
{
|
2006-07-24 03:33:26 +02:00
|
|
|
if(decay_rate <= 0)
|
|
|
|
return cur;
|
|
|
|
return std::max(0.0f, cur - timestep / 1000.0f * decay_rate * limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::CalculateRegen(float timestep)
|
|
|
|
{
|
|
|
|
// Health regen
|
|
|
|
if(entf_get(ENTF_HEALTH_DECAY))
|
|
|
|
m_healthCurr = decay(m_healthCurr, m_healthMax, timestep, m_healthDecayRate);
|
|
|
|
else if(g_Game->GetTime() - m_lastCombatTime > m_healthRegenStart)
|
|
|
|
m_healthCurr = regen(m_healthCurr, m_healthMax, timestep, m_healthRegenRate);
|
|
|
|
|
|
|
|
// Stamina regen
|
|
|
|
if( m_staminaMax > 0 )
|
2006-01-21 12:17:15 +01:00
|
|
|
{
|
2006-07-24 03:33:26 +02:00
|
|
|
if(entf_get(ENTF_IS_RUNNING))
|
|
|
|
m_staminaCurr = decay(m_staminaCurr, m_staminaMax, timestep, m_runDecayRate);
|
|
|
|
else if(m_orderQueue.empty())
|
|
|
|
m_staminaCurr = regen(m_staminaCurr, m_staminaMax, timestep, m_runRegenRate);
|
2006-01-21 12:17:15 +01:00
|
|
|
}
|
2006-06-22 00:37:31 +02:00
|
|
|
}
|
2007-01-25 08:00:31 +01:00
|
|
|
|
|
|
|
void CEntity::ExitAuras()
|
|
|
|
{
|
|
|
|
for( AuraSet::iterator it = m_aurasInfluencingMe.begin(); it != m_aurasInfluencingMe.end(); it++ )
|
|
|
|
{
|
|
|
|
(*it)->Remove( this );
|
|
|
|
}
|
|
|
|
m_aurasInfluencingMe.clear();
|
|
|
|
}
|