1
0
forked from 0ad/0ad

# 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:
Matei 2006-07-24 01:33:26 +00:00
parent 1ce5ab6e0c
commit 2261231ffa
13 changed files with 237 additions and 195 deletions

View File

@ -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.

View File

@ -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 ) )
{

View File

@ -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 );

View File

@ -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);
}
}
/*

View File

@ -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();

View File

@ -13,7 +13,7 @@
class CVector2D;
class CEntity;
struct CEntityList;
struct SClassSet;
class CClassSet;
class CEntityFormation
{

View File

@ -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 )

View File

@ -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 );

View File

@ -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

View 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;
}
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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.