forked from 0ad/0ad
Matei
fa229121ec
- Added "Screenshot Mode" and "Fog of War" game attributes. (Screenshot Mode causes units to be initialized to Hold stance instead of Aggress and also forces LOS to be All Visible. Atlas turn on Screenshot Mode by default so units don't try to kill each other in there.) - Modified LOSManager to allow disabling fog of war. - Removed some debug message spam. - Enabled line antialiasing for aura rendering and fixed some bugs that caused strange effects (color was not set properly for the center point, and when a unit was both mouseover'ed and selected, the aura was drawn twice). - Modified Stand stance to allow retaliation on attacks (normally Stand will attack any enemy in LOS, but this is useful if a neutral unit is in LOS). - Modified pathfinder to not take into account terrain slope, which is an expensive calculation - we'll eventually take into account terrain type instead. This was SVN commit r4527.
178 lines
4.8 KiB
C++
178 lines
4.8 KiB
C++
#include "precompiled.h"
|
|
|
|
#include "Stance.h"
|
|
|
|
#include "EntityManager.h"
|
|
#include "Entity.h"
|
|
#include "ps/Player.h"
|
|
#include "graphics/Terrain.h"
|
|
|
|
#include <algorithm>
|
|
|
|
// AggressStance ////////////////////////////////////////////////////
|
|
|
|
void CAggressStance::onIdle()
|
|
{
|
|
CEntity* target = CStanceUtils::chooseTarget( m_Entity );
|
|
if( target )
|
|
CStanceUtils::attack( m_Entity, target );
|
|
}
|
|
|
|
void CAggressStance::onDamaged(CEntity *source)
|
|
{
|
|
if( source && m_Entity->m_orderQueue.empty()
|
|
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
|
|
CStanceUtils::attack( m_Entity, source );
|
|
}
|
|
|
|
// StandStance //////////////////////////////////////////////////////
|
|
|
|
void CStandStance::onIdle()
|
|
{
|
|
CEntity* target = CStanceUtils::chooseTarget( m_Entity );
|
|
if( target )
|
|
CStanceUtils::attack( m_Entity, target );
|
|
}
|
|
|
|
void CStandStance::onDamaged(CEntity *source)
|
|
{
|
|
if( source && m_Entity->m_orderQueue.empty()
|
|
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
|
|
CStanceUtils::attack( m_Entity, source );
|
|
}
|
|
|
|
// DefendStance /////////////////////////////////////////////////////
|
|
|
|
void CDefendStance::onIdle()
|
|
{
|
|
idlePos = CVector2D( m_Entity->m_position.X, m_Entity->m_position.Z );
|
|
|
|
CEntity* target = CStanceUtils::chooseTarget( m_Entity );
|
|
if( target )
|
|
CStanceUtils::attack( m_Entity, target );
|
|
}
|
|
|
|
void CDefendStance::onDamaged(CEntity *source)
|
|
{
|
|
if( source && m_Entity->m_orderQueue.empty()
|
|
&& m_Entity->GetPlayer()->GetDiplomaticStance(source->GetPlayer()) != DIPLOMACY_ALLIED )
|
|
{
|
|
// Retaliate only if we can reach the enemy unit without walking farther than our LOS
|
|
// radius away from idlePos.
|
|
int action = m_Entity->GetAttackAction( source->me );
|
|
if( action )
|
|
{
|
|
float range = m_Entity->m_actions[action].m_MaxRange;
|
|
if( ( range + m_Entity->m_los * CELL_SIZE ) >= m_Entity->distance2D( source ) )
|
|
{
|
|
CEntityOrder order( CEntityOrder::ORDER_GENERIC, CEntityOrder::SOURCE_UNIT_AI );
|
|
order.m_data[0].entity = source->me;
|
|
order.m_data[1].data = action;
|
|
m_Entity->pushOrder( order );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CDefendStance::checkMovement( CVector2D proposedPos )
|
|
{
|
|
float los = m_Entity->m_los*CELL_SIZE;
|
|
|
|
// Check that we haven't moved too far from the place where we were stationed.
|
|
if( (proposedPos - idlePos).length() > los )
|
|
{
|
|
// TODO: Make sure we don't clear any player orders here; the best way would be to make
|
|
// shift-clicked player orders either unqueue any AI orders or convert those AI orders
|
|
// to player orders (since the player wants us to finish our attack then do other stuff).
|
|
m_Entity->m_orderQueue.clear();
|
|
|
|
// Try to find some other nearby enemy to attack, provided it's also in range of our idle spot
|
|
// TODO: really we should be attack-moving to our spot somehow
|
|
|
|
std::vector<CEntity*> results;
|
|
g_EntityManager.GetInRange( m_Entity->m_position.X, m_Entity->m_position.Z, los, results );
|
|
|
|
float bestDist = 1e20f;
|
|
CEntity* bestTarget = 0;
|
|
|
|
for( size_t i=0; i<results.size(); i++ )
|
|
{
|
|
CEntity* ent = results[i];
|
|
float range = m_Entity->m_actions[m_Entity->GetAttackAction(ent->me)].m_MaxRange;
|
|
if( m_Entity->GetPlayer()->GetDiplomaticStance( ent->GetPlayer() ) == DIPLOMACY_ENEMY )
|
|
{
|
|
float distToMe = ent->distance2D( m_Entity );
|
|
float distToIdlePos = ent->distance2D( idlePos );
|
|
if( distToIdlePos <= los+range && distToMe < bestDist )
|
|
{
|
|
bestDist = distToMe;
|
|
bestTarget = ent;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bestTarget != 0 )
|
|
{
|
|
CStanceUtils::attack( m_Entity, bestTarget );
|
|
}
|
|
else
|
|
{
|
|
// Let's just walk back to our idle spot
|
|
CEntityOrder order( CEntityOrder::ORDER_GOTO, CEntityOrder::SOURCE_UNIT_AI );
|
|
order.m_data[0].location = idlePos;
|
|
m_Entity->pushOrder( order );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// StanceUtils //////////////////////////////////////////////////////
|
|
|
|
void CStanceUtils::attack(CEntity* entity, CEntity* target)
|
|
{
|
|
int action = entity->GetAttackAction( target->me );
|
|
if( action )
|
|
{
|
|
CEntityOrder order( CEntityOrder::ORDER_GENERIC, CEntityOrder::SOURCE_UNIT_AI );
|
|
order.m_data[0].entity = target->me;
|
|
order.m_data[1].data = action;
|
|
entity->pushOrder( order );
|
|
}
|
|
}
|
|
|
|
CEntity* CStanceUtils::chooseTarget( CEntity* entity )
|
|
{
|
|
return chooseTarget( entity->m_position.X, entity->m_position.Z, entity->m_los*CELL_SIZE, entity->GetPlayer() );
|
|
}
|
|
|
|
CEntity* CStanceUtils::chooseTarget( float x, float z, float radius, CPlayer* myPlayer )
|
|
{
|
|
std::vector<CEntity*> results;
|
|
g_EntityManager.GetInRange( x, z, radius, results );
|
|
|
|
float bestDist = 1e20f;
|
|
CEntity* bestTarget = 0;
|
|
|
|
for( size_t i=0; i<results.size(); i++ )
|
|
{
|
|
CEntity* ent = results[i];
|
|
if( myPlayer->GetDiplomaticStance( ent->GetPlayer() ) == DIPLOMACY_ENEMY )
|
|
{
|
|
float dist = ent->distance2D( x, z );
|
|
if( dist < bestDist )
|
|
{
|
|
bestDist = dist;
|
|
bestTarget = ent;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestTarget;
|
|
}
|
|
|