# Housekeeping.
Jan and I implemented a number of changes: - Converted SClassSet to vector. - Refactored get/set ClassSet from string into methods in CClassSet. - Turned pass-by-value string params in getCollisionObject, CEntity constructor and CEntityManager into pointers. - Simplified processChooseMovement. - Merged CalculateRun and CalculateHealth into a single, simpler CalculateRegen + helper functions. - Changed the way regen works so the rates read in the XML act as rates (before, they were the number of seconds until the entity will be fully regenned, which is a bit counterintuitive). This was SVN commit r4167.
This commit is contained in:
parent
1ce5ab6e0c
commit
2261231ffa
@ -1445,7 +1445,7 @@ void CBuildingPlacer::update( float timeStep )
|
||||
{
|
||||
// If we're on a socket of our type, remember that and snap ourselves to it
|
||||
m_bounds->setPosition(pos.X, pos.Z); // first, move bounds to mouse pos
|
||||
CEntity* ent = getCollisionEntity( m_bounds, 0, L"" ); // now, check what we intersect
|
||||
CEntity* ent = getCollisionEntity( m_bounds, 0 ); // now, check what we intersect
|
||||
if( ent && ent->m_classes.IsMember( m_template->m_socket ) ) // if it's a socket, snap to it
|
||||
{
|
||||
onSocket = true;
|
||||
@ -1482,7 +1482,7 @@ void CBuildingPlacer::update( float timeStep )
|
||||
CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
|
||||
m_valid = pTerrain->isOnMap( pos.X, pos.Z )
|
||||
&& ( m_template->m_socket == L"" || onSocket )
|
||||
&& ( getCollisionObject( m_bounds, 0, m_template->m_socket ) == 0 );
|
||||
&& ( getCollisionObject( m_bounds, 0, &m_template->m_socket ) == 0 );
|
||||
|
||||
// Flash our actor red if the position is invalid.
|
||||
|
||||
|
@ -45,7 +45,7 @@ CEntity* GetCollisionObject( float x, float y )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player, CStrW ignoreClass )
|
||||
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 );
|
||||
@ -60,7 +60,7 @@ CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player, C
|
||||
is passed in and the same player as the unit, then ignore the (potential) collision */
|
||||
if( player && (*it)->m_passThroughAllies && (*it)->m_player == player ) continue;
|
||||
|
||||
if( (*it)->m_classes.IsMember( ignoreClass ) ) continue;
|
||||
if( ignoreClass && (*it)->m_classes.IsMember( *ignoreClass ) ) continue;
|
||||
|
||||
if( bounds->intersects( (*it)->m_bounds ) )
|
||||
{
|
||||
@ -72,7 +72,7 @@ CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player, C
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player, CStrW ignoreClass )
|
||||
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 );
|
||||
@ -87,7 +87,7 @@ CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player, CStrW ign
|
||||
is passed in and the same player as the unit, then ignore the (potential) collision */
|
||||
if( player && (*it)->m_passThroughAllies && (*it)->m_player == player ) continue;
|
||||
|
||||
if( (*it)->m_classes.IsMember( ignoreClass ) ) continue;
|
||||
if( ignoreClass && (*it)->m_classes.IsMember( *ignoreClass ) ) continue;
|
||||
|
||||
if( bounds->intersects( (*it)->m_bounds ) )
|
||||
{
|
||||
|
@ -34,8 +34,8 @@ typedef std::vector<CEntity*> RayIntersects;
|
||||
|
||||
HEntity getCollisionObject( CEntity* entity );
|
||||
HEntity getCollisionObject( CEntity* entity, float x, float y );
|
||||
CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player=0, CStrW ignoreClass=L"" );
|
||||
CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player=0, CStrW ignoreClass=L"" );
|
||||
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 );
|
||||
|
@ -36,7 +36,7 @@ extern int g_xres, g_yres;
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
CEntity::CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, const CStrW& building )
|
||||
CEntity::CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, const CStrW* building )
|
||||
{
|
||||
ent_flags = 0;
|
||||
|
||||
@ -101,7 +101,8 @@ CEntity::CEntity( CEntityTemplate* base, CVector3D position, float orientation,
|
||||
m_formation = -1;
|
||||
m_grouped = -1;
|
||||
|
||||
m_building = building;
|
||||
if( building )
|
||||
m_building = *building;
|
||||
|
||||
m_extant = true;
|
||||
m_visible = true;
|
||||
@ -265,64 +266,17 @@ void CEntity::snapToGround()
|
||||
m_graphics_position.Y = getAnchorLevel( m_graphics_position.X, m_graphics_position.Z );
|
||||
}
|
||||
|
||||
|
||||
jsval CEntity::getClassSet()
|
||||
{
|
||||
STL_HASH_SET<CStrW, CStrW_hash_compare>::iterator it;
|
||||
it = m_classes.m_Set.begin();
|
||||
CStrW result = L"";
|
||||
if( it != m_classes.m_Set.end() )
|
||||
{
|
||||
result = *( it++ );
|
||||
for( ; it != m_classes.m_Set.end(); it++ )
|
||||
result += L" " + *it;
|
||||
}
|
||||
CStrW result = m_classes.getMemberList();
|
||||
return( ToJSVal( result ) );
|
||||
}
|
||||
|
||||
void CEntity::setClassSet( jsval value )
|
||||
{
|
||||
// Get the set that was passed in.
|
||||
CStr temp = ToPrimitive<CStrW>( value );
|
||||
CStr entry;
|
||||
|
||||
m_classes.m_Added.clear();
|
||||
m_classes.m_Removed.clear();
|
||||
|
||||
while( true )
|
||||
{
|
||||
long brk_sp = temp.Find( ' ' );
|
||||
long brk_cm = temp.Find( ',' );
|
||||
long brk = ( brk_sp == -1 ) ? brk_cm : ( brk_cm == -1 ) ? brk_sp : ( brk_sp < brk_cm ) ? brk_sp : brk_cm;
|
||||
|
||||
if( brk == -1 )
|
||||
{
|
||||
entry = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = temp.GetSubstring( 0, brk );
|
||||
temp = temp.GetSubstring( brk + 1, temp.Length() );
|
||||
}
|
||||
|
||||
if( brk != 0 )
|
||||
{
|
||||
if( entry[0] == '-' )
|
||||
{
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_classes.m_Removed.push_back( entry );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( entry[0] == '+' )
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_classes.m_Added.push_back( entry );
|
||||
}
|
||||
}
|
||||
if( brk == -1 )
|
||||
break;
|
||||
}
|
||||
CStr memberCmdList = ToPrimitive<CStrW>( value );
|
||||
m_classes.setFromMemberList(memberCmdList);
|
||||
|
||||
rebuildClassSet();
|
||||
}
|
||||
@ -340,8 +294,7 @@ void CEntity::update( size_t timestep )
|
||||
m_position_previous = m_position;
|
||||
m_orientation_previous = m_orientation;
|
||||
|
||||
CalculateRun( timestep );
|
||||
CalculateHealth( timestep );
|
||||
CalculateRegen( timestep );
|
||||
|
||||
if ( entf_get(ENTF_TRIGGER_RUN) )
|
||||
m_frameCheck++;
|
||||
@ -1023,7 +976,7 @@ void CEntity::renderSelectionOutline( float alpha )
|
||||
if( !m_bounds || !m_visible )
|
||||
return;
|
||||
|
||||
if( getCollisionObject( m_bounds, m_player, m_base->m_socket ) )
|
||||
if( getCollisionObject( m_bounds, m_player, &m_base->m_socket ) )
|
||||
{
|
||||
glColor4f( 1.0f, 0.5f, 0.5f, alpha ); // We're colliding with another unit; colour outline pink
|
||||
}
|
||||
@ -1413,31 +1366,41 @@ void CEntity::renderRallyPoint()
|
||||
sprite.Render();
|
||||
}
|
||||
|
||||
void CEntity::CalculateRun(float timestep)
|
||||
|
||||
static inline float regen(float cur, float limit, float timestep, float regen_rate)
|
||||
{
|
||||
if( m_staminaMax > 0 )
|
||||
{
|
||||
if ( entf_get(ENTF_IS_RUNNING) && m_runDecayRate > 0 )
|
||||
{
|
||||
m_staminaCurr = max( 0.0f, m_staminaCurr - timestep / 1000.0f / m_runDecayRate * m_staminaMax );
|
||||
}
|
||||
else if ( m_orderQueue.empty() && m_runRegenRate > 0 )
|
||||
{
|
||||
m_staminaCurr = min( m_staminaMax, m_staminaCurr + timestep / 1000.0f / m_runRegenRate * m_staminaMax );
|
||||
}
|
||||
}
|
||||
if(regen_rate <= 0)
|
||||
return cur;
|
||||
return std::min(limit, cur + timestep / 1000.0f * regen_rate * limit );
|
||||
}
|
||||
|
||||
void CEntity::CalculateHealth(float timestep)
|
||||
static inline float decay(float cur, float limit, float timestep, float decay_rate)
|
||||
{
|
||||
if ( entf_get(ENTF_HEALTH_DECAY) && m_healthDecayRate > 0 )
|
||||
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 )
|
||||
{
|
||||
m_healthCurr = max( 0.0f, m_healthCurr - timestep / 1000.0f / m_healthDecayRate * m_healthMax );
|
||||
}
|
||||
else if ( m_healthRegenRate > 0 && g_Game->GetTime() - m_lastCombatTime > m_healthRegenStart )
|
||||
{
|
||||
m_healthCurr = min( m_healthMax, m_healthCurr + timestep / 1000.0f / m_healthRegenRate * m_healthMax );
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -98,7 +98,7 @@ public:
|
||||
CEntityTemplate* m_base;
|
||||
|
||||
// The class types this entity has
|
||||
SClassSet m_classes;
|
||||
CClassSet m_classes;
|
||||
|
||||
// Production queue
|
||||
CProductionQueue* m_productionQueue;
|
||||
@ -275,7 +275,7 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, const CStrW& building = L"" );
|
||||
CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, const CStrW* building = 0 );
|
||||
|
||||
uint processGotoHelper( CEntityOrder* current, size_t timestep_milli, HEntity& collide );
|
||||
|
||||
@ -294,6 +294,8 @@ private:
|
||||
bool processPatrol( CEntityOrder* current, size_t timestep_milli );
|
||||
|
||||
float processChooseMovement( float distance );
|
||||
|
||||
bool shouldRun( float distance ); // Given our distance to a target, can we be running?
|
||||
|
||||
public:
|
||||
~CEntity();
|
||||
@ -365,8 +367,7 @@ public:
|
||||
void repath();
|
||||
|
||||
//Calculate stamina points
|
||||
void CalculateRun(float timestep);
|
||||
void CalculateHealth(float timestep);
|
||||
void CalculateRegen(float timestep);
|
||||
|
||||
// Reset properties after the entity-template we use changes.
|
||||
void loadBase();
|
||||
|
@ -13,7 +13,7 @@
|
||||
class CVector2D;
|
||||
class CEntity;
|
||||
struct CEntityList;
|
||||
struct SClassSet;
|
||||
class CClassSet;
|
||||
|
||||
class CEntityFormation
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ void CEntityManager::deleteAll()
|
||||
}
|
||||
|
||||
HEntity CEntityManager::create( CEntityTemplate* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections,
|
||||
CStrW building)
|
||||
const CStrW* building)
|
||||
{
|
||||
debug_assert( base );
|
||||
if( !base )
|
||||
@ -99,7 +99,7 @@ HEntity CEntityManager::create( CEntityTemplate* base, CVector3D position, float
|
||||
return( HEntity( m_nextalloc++ ) );
|
||||
}
|
||||
|
||||
HEntity CEntityManager::create( const CStrW& templateName, CPlayer* player, CVector3D position, float orientation, CStrW building )
|
||||
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 );
|
||||
@ -123,8 +123,9 @@ HEntity CEntityManager::createFoundation( const CStrW& templateName, CPlayer* pl
|
||||
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 );
|
||||
return create( foundation, position, orientation, selections, &templateName );
|
||||
}
|
||||
|
||||
HEntity* CEntityManager::getByHandle( u16 index )
|
||||
|
@ -56,10 +56,10 @@ public:
|
||||
~CEntityManager();
|
||||
|
||||
HEntity create( CEntityTemplate* base, CVector3D position, float orientation,
|
||||
const std::set<CStrW>& actorSelections, CStrW building = L"" );
|
||||
const std::set<CStrW>& actorSelections, const CStrW* building = 0 );
|
||||
|
||||
HEntity create( const CStrW& templateName, CPlayer* player, CVector3D position,
|
||||
float orientation, CStrW building = L"" );
|
||||
float orientation, const CStrW* building = 0 );
|
||||
|
||||
HEntity createFoundation( const CStrW& templateName, CPlayer* player, CVector3D position,
|
||||
float orientation );
|
||||
|
@ -31,43 +31,52 @@ enum EGotoSituation
|
||||
WOULD_LEAVE_MAP
|
||||
};
|
||||
|
||||
bool CEntity::shouldRun(float distance)
|
||||
{
|
||||
if (!entf_get(ENTF_SHOULD_RUN))
|
||||
return false;
|
||||
|
||||
// tired
|
||||
if(m_staminaCurr <= 0)
|
||||
return false;
|
||||
|
||||
if(distance >= m_runMaxRange)
|
||||
return false;
|
||||
|
||||
// don't start running if less than minimum
|
||||
if( distance <= m_runMinRange && !entf_get(ENTF_IS_RUNNING) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float CEntity::processChooseMovement( float distance )
|
||||
{
|
||||
// Should we run or walk
|
||||
if (entf_get(ENTF_SHOULD_RUN) && m_staminaCurr > 0 && distance < m_runMaxRange &&
|
||||
( distance > m_runMinRange || entf_get(ENTF_IS_RUNNING) ) )
|
||||
{
|
||||
if ( m_actor )
|
||||
{
|
||||
if ( !m_actor->IsPlayingAnimation( "run" ) )
|
||||
{
|
||||
m_actor->SetEntitySelection( L"run" );
|
||||
m_actor->SetRandomAnimation( "run", false, m_runSpeed );
|
||||
bool should_run = shouldRun(distance);
|
||||
|
||||
const float speed = should_run? m_runSpeed : m_speed;
|
||||
const char* anim_name = should_run? "run" : "walk";
|
||||
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( rand( 0, 1000 ) / 1000.0f );
|
||||
entf_set(ENTF_IS_RUNNING);
|
||||
}
|
||||
}
|
||||
return m_runSpeed;
|
||||
}
|
||||
else
|
||||
// TODO: the animation code requires unicode for now. will be changed to
|
||||
// 8bit later (for consistency; note that filenames etc. need not be
|
||||
// unicode), so remove this then.
|
||||
const CStrW u_anim_name = anim_name;
|
||||
|
||||
if ( m_actor )
|
||||
{
|
||||
if ( m_actor )
|
||||
if ( !m_actor->IsPlayingAnimation( anim_name ) )
|
||||
{
|
||||
// Should we update animation?
|
||||
if ( !m_actor->IsPlayingAnimation( "walk" ) )
|
||||
{
|
||||
m_actor->SetEntitySelection( L"walk" );
|
||||
m_actor->SetRandomAnimation( "walk", false, m_speed );
|
||||
m_actor->SetEntitySelection( u_anim_name );
|
||||
m_actor->SetRandomAnimation( anim_name, false, speed );
|
||||
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( rand( 0, 1000 ) / 1000.0f );
|
||||
entf_clear(ENTF_IS_RUNNING);
|
||||
}
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( rand( 0, 1000 ) / 1000.0f );
|
||||
|
||||
entf_set_to(ENTF_IS_RUNNING, should_run);
|
||||
}
|
||||
return m_speed;
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
// Does all the shared processing for line-of-sight gotos
|
||||
|
123
source/simulation/EntitySupport.cpp
Normal file
123
source/simulation/EntitySupport.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
#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.GetSubstring( 0, brk );
|
||||
temp = temp.GetSubstring( brk + 1, temp.Length() );
|
||||
}
|
||||
|
||||
if( brk != 0 )
|
||||
{
|
||||
if( entry[0] == '-' )
|
||||
{
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_RemovedMembers.push_back( entry );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( entry[0] == '+' )
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_AddedMembers.push_back( entry );
|
||||
}
|
||||
}
|
||||
if( brk == -1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -19,37 +19,26 @@ struct SEntityAction
|
||||
: m_MinRange(minRange), m_MaxRange(maxRange), m_Speed(speed), m_Animation(animation) {}
|
||||
};
|
||||
|
||||
struct SClassSet
|
||||
class CClassSet
|
||||
{
|
||||
SClassSet* m_Parent;
|
||||
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
|
||||
|
||||
typedef STL_HASH_SET<CStrW, CStrW_hash_compare> ClassSet;
|
||||
public:
|
||||
CClassSet() : m_Parent(NULL) {}
|
||||
|
||||
ClassSet m_Set;
|
||||
std::vector<CStrW> m_Added;
|
||||
std::vector<CStrW> m_Removed;
|
||||
bool IsMember( const CStrW& Test );
|
||||
|
||||
void Rebuild();
|
||||
|
||||
inline SClassSet() { m_Parent = NULL; }
|
||||
|
||||
inline bool IsMember( const CStrW& Test )
|
||||
{ return( m_Set.find( Test ) != m_Set.end() ); }
|
||||
|
||||
inline void SetParent( SClassSet* Parent )
|
||||
inline void SetParent( CClassSet* Parent )
|
||||
{ m_Parent = Parent; Rebuild(); }
|
||||
|
||||
void Rebuild()
|
||||
{
|
||||
if( m_Parent )
|
||||
m_Set = m_Parent->m_Set;
|
||||
else
|
||||
m_Set.clear();
|
||||
|
||||
std::vector<CStrW>::iterator it;
|
||||
for( it = m_Removed.begin(); it != m_Removed.end(); it++ )
|
||||
m_Set.erase( *it );
|
||||
for( it = m_Added.begin(); it != m_Added.end(); it++ )
|
||||
m_Set.insert( *it );
|
||||
}
|
||||
CStrW getMemberList();
|
||||
void setFromMemberList(const CStrW& list);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -86,58 +86,14 @@ void CEntityTemplate::loadBase()
|
||||
|
||||
jsval CEntityTemplate::getClassSet()
|
||||
{
|
||||
STL_HASH_SET<CStrW, CStrW_hash_compare>::iterator it;
|
||||
it = m_classes.m_Set.begin();
|
||||
CStrW result = *( it++ );
|
||||
for( ; it != m_classes.m_Set.end(); it++ )
|
||||
result += L" " + *it;
|
||||
CStrW result = m_classes.getMemberList();
|
||||
return( ToJSVal( result ) );
|
||||
}
|
||||
|
||||
void CEntityTemplate::setClassSet( jsval value )
|
||||
{
|
||||
// Get the set that was passed in.
|
||||
CStr temp = ToPrimitive<CStrW>( value );
|
||||
CStr entry;
|
||||
|
||||
m_classes.m_Added.clear();
|
||||
m_classes.m_Removed.clear();
|
||||
|
||||
while( true )
|
||||
{
|
||||
long brk_sp = temp.Find( ' ' );
|
||||
long brk_cm = temp.Find( ',' );
|
||||
long brk = ( brk_sp == -1 ) ? brk_cm : ( brk_cm == -1 ) ? brk_sp : ( brk_sp < brk_cm ) ? brk_sp : brk_cm;
|
||||
|
||||
if( brk == -1 )
|
||||
{
|
||||
entry = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = temp.GetSubstring( 0, brk );
|
||||
temp = temp.GetSubstring( brk + 1, temp.Length() );
|
||||
}
|
||||
|
||||
if( brk != 0 )
|
||||
{
|
||||
|
||||
if( entry[0] == '-' )
|
||||
{
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_classes.m_Removed.push_back( entry );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( entry[0] == '+' )
|
||||
entry = entry.GetSubstring( 1, entry.Length() );
|
||||
if( entry.Length() )
|
||||
m_classes.m_Added.push_back( entry );
|
||||
}
|
||||
}
|
||||
if( brk == -1 ) break;
|
||||
}
|
||||
CStr memberCmdList = ToPrimitive<CStrW>( value );
|
||||
m_classes.setFromMemberList(memberCmdList);
|
||||
|
||||
rebuildClassSet();
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
CEntityTemplate* m_unmodified;
|
||||
|
||||
// The class types this entity has
|
||||
SClassSet m_classes;
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user