Added serverGame library

This commit is contained in:
Anonymous
2014-01-15 03:59:18 -07:00
parent 89291fb38c
commit 0196cf51d0
1032 changed files with 256379 additions and 0 deletions
@@ -0,0 +1,54 @@
// ======================================================================
//
// AiCreatureStateArchive.cpp
// copyright 2005 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiCreatureStateArchive.h"
#include "serverGame/AiCreatureController.h"
#include "serverGame/CreatureObject.h"
#include "serverNetworkMessages/AiCreatureStateMessage.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedObject/NetworkIdManager.h"
//-----------------------------------------------------------------------
namespace Archive
{
// The archive functions for AiCreatureStateMessage are here so we don't have to link serverGame with everything
void get(ReadIterator & source, AiCreatureStateMessage & target)
{
get(source, target.m_networkId);
get(source, target.m_movement);
#ifdef _DEBUG
Object * const object = NetworkIdManager::getObjectById(target.m_networkId);
if (object == NULL)
{
WARNING(true, ("AiCreatureStateArchive::get() Unable to resolve networkId(%s) to an Object", target.m_networkId.getValueString().c_str()));
return;
}
AICreatureController * const controller = (object != NULL) ? AICreatureController::asAiCreatureController(object->getController()) : NULL;
if (controller == NULL)
{
WARNING(true, ("AiCreatureStateArchive::get() Message to object(%s) that does not have an AICreatureController", object->getDebugInformation().c_str()));
return;
}
#endif // _DEBUG
}
void put(ByteStream & target, AiCreatureStateMessage const & source)
{
put(target, source.m_networkId);
put(target, source.m_movement);
}
}
//=======================================================================
@@ -0,0 +1,27 @@
// ======================================================================
//
// AiCreatureStateArchive.h
// copyright 2005 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiCreatureStateArchive_H
#define INCLUDED_AiCreatureStateArchive_H
class AiCreatureStateMessage;
// ======================================================================
namespace Archive
{
class ReadIterator;
class ByteStream;
void get(ReadIterator & source, AiCreatureStateMessage & target);
void put(ByteStream & target, AiCreatureStateMessage const & source);
};
// ======================================================================
#endif // INCLUDED_AiCreatureStateArchive_H
@@ -0,0 +1,639 @@
// ======================================================================
//
// AiLocation.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiLocation.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ServerObject.h"
#include "serverGame/ServerWorld.h"
#include "sharedCollision/CollisionUtils.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedObject/CellProperty.h"
#include "sharedObject/NetworkIdManager.h"
#include "sharedObject/World.h"
#include "sharedTerrain/TerrainObject.h"
static int gs_debugCounter = -6000000;
const AiLocation AiLocation::invalid;
namespace AiLocationArchive
{
// define some values for data combinations so we don't have to send
// all the location data over the network
enum AiLocationPackage
{
ALP_None, // uninitialized location
ALP_Cell, // cell id, local position, radius
ALP_World, // world position, radius
ALP_Object, // object id
ALP_OffsetObject, // object id, offset, relative flag
};
}
#define AI_WARNING(A) WARNING(ConfigServerGame::getReportAiWarnings(),(A);
// ----------------------------------------------------------------------
AiLocation::AiLocation ( void )
: m_valid(false),
m_attached(false),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(Vector::zero),
m_position_w(Vector::zero),
m_radius(0.0f),
m_offset_p(Vector::zero),
m_relativeOffset(false),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
}
AiLocation::AiLocation ( CellProperty const * cell, Vector const & position, float radius )
: m_valid(true),
m_attached(false),
m_object(NULL),
m_objectId(),
m_cellObject(cell ? &cell->getOwner() : NULL),
m_position_p(position),
m_position_w(CollisionUtils::transformToWorld(cell,position)),
m_radius(radius),
m_offset_p(Vector::zero),
m_relativeOffset(false),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
VALIDATE_LOCATION();
}
AiLocation::AiLocation ( NetworkId const & cellId, Vector const & position, float radius )
: m_valid(true),
m_attached(false),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(position),
m_position_w(position),
m_radius(radius),
m_offset_p(Vector::zero),
m_relativeOffset(false),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
if(cellId.isValid())
{
m_cellObject = NetworkIdManager::getObjectById(cellId);
}
else
{
m_cellObject = &CellProperty::getWorldCellProperty()->getOwner();
}
if(m_cellObject)
{
m_position_w = CollisionUtils::transformToWorld(m_cellObject->getCellProperty(),m_position_p);
}
VALIDATE_LOCATION();
}
AiLocation::AiLocation ( Object const * object )
: m_valid(true),
m_attached(true),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(Vector::zero),
m_position_w(Vector::zero),
m_radius(0.0f),
m_offset_p(Vector::zero),
m_relativeOffset(false),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
setObject(object);
VALIDATE_LOCATION();
}
AiLocation::AiLocation ( NetworkId const & objectId )
: m_valid(true),
m_attached(true),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(Vector::zero),
m_position_w(Vector::zero),
m_radius(0.0f),
m_offset_p(Vector::zero),
m_relativeOffset(false),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
setObject(NetworkIdManager::getObjectById(objectId));
VALIDATE_LOCATION();
}
AiLocation::AiLocation ( Object const * object, Vector const & offset, bool relativeOffset )
: m_valid(true),
m_attached(true),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(Vector::zero),
m_position_w(Vector::zero),
m_radius(0.0f),
m_offset_p(offset),
m_relativeOffset(relativeOffset),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
setObject(object);
VALIDATE_LOCATION();
}
AiLocation::AiLocation ( NetworkId const & objectId, Vector const & offset, bool relativeOffset )
: m_valid(true),
m_attached(true),
m_object(NULL),
m_objectId(),
m_cellObject(NULL),
m_position_p(Vector::zero),
m_position_w(Vector::zero),
m_radius(0.0f),
m_offset_p(offset),
m_relativeOffset(relativeOffset),
m_hasChanged(true),
m_cuttable(true),
m_debugId(gs_debugCounter++)
{
setObject(NetworkIdManager::getObjectById(objectId));
VALIDATE_LOCATION();
}
// ----------
AiLocation::AiLocation ( AiLocation const & loc )
: m_valid(loc.m_valid),
m_attached(loc.m_attached),
m_object(loc.m_object),
m_objectId(loc.m_objectId),
m_cellObject(loc.m_cellObject),
m_position_p(loc.m_position_p),
m_position_w(loc.m_position_w),
m_radius(loc.m_radius),
m_offset_p(loc.m_offset_p),
m_relativeOffset(loc.m_relativeOffset),
m_hasChanged(true),
m_cuttable(loc.m_cuttable),
m_debugId(gs_debugCounter++)
{
}
// ----------
AiLocation::AiLocation ( Archive::ReadIterator & source )
: m_valid(),
m_attached(),
m_object(),
m_objectId(),
m_cellObject(),
m_position_p(),
m_position_w(),
m_radius(),
m_offset_p(),
m_relativeOffset(),
m_hasChanged(),
m_cuttable(),
m_debugId()
{
unpack(source);
}
// ----------
AiLocation::~AiLocation()
{
}
// ----------
AiLocation & AiLocation::operator = ( AiLocation const & loc )
{
m_valid = loc.m_valid;
m_attached = loc.m_attached;
m_object = loc.m_object;
m_objectId = loc.m_objectId;
m_cellObject = loc.m_cellObject;
m_position_p = loc.m_position_p;
m_position_w = loc.m_position_w;
m_radius = loc.m_radius;
m_offset_p = loc.m_offset_p;
m_relativeOffset = loc.m_relativeOffset;
m_hasChanged = true;
m_cuttable = loc.m_cuttable;
VALIDATE_LOCATION();
return *this;
}
// ----------
void AiLocation::pack(Archive::ByteStream & target) const
{
Archive::put(target, m_valid);
Archive::put(target, m_attached);
Archive::put(target, m_relativeOffset);
Archive::put(target, m_hasChanged);
Archive::put(target, m_cuttable);
Archive::put(target, m_debugId);
Archive::put(target, m_radius);
if (getObjectId() != NetworkId::cms_invalid)
{
if (getOffset() == Vector::zero)
{
Archive::put(target, static_cast<uint8>(AiLocationArchive::ALP_Object));
Archive::put(target, getObjectId());
}
else
{
Archive::put(target, static_cast<uint8>(AiLocationArchive::ALP_OffsetObject));
Archive::put(target, getObjectId());
Archive::put(target, getOffset());
}
}
else if (getCellId() != NetworkId::cms_invalid)
{
Archive::put(target, static_cast<uint8>(AiLocationArchive::ALP_Cell));
Archive::put(target, getCellId());
Archive::put(target, getPosition_p());
}
else
{
Archive::put(target, static_cast<uint8>(AiLocationArchive::ALP_World));
Archive::put(target, getPosition_w());
}
}
// ----------
void AiLocation::unpack( Archive::ReadIterator & source )
{
Archive::get(source, m_valid);
Archive::get(source, m_attached);
Archive::get(source, m_relativeOffset);
Archive::get(source, m_hasChanged);
Archive::get(source, m_cuttable);
Archive::get(source, m_debugId);
Archive::get(source, m_radius);
uint8 package;
Archive::get(source, package);
switch (static_cast<AiLocationArchive::AiLocationPackage>(package))
{
case AiLocationArchive::ALP_None:
// do nothing
break;
case AiLocationArchive::ALP_Cell:
{
NetworkId cellId;
Archive::get(source, cellId);
Archive::get(source, m_position_p);
m_position_w = m_position_p;
if (cellId.isValid())
{
m_cellObject = NetworkIdManager::getObjectById(cellId);
}
else
{
m_cellObject = &CellProperty::getWorldCellProperty()->getOwner();
}
if (m_cellObject)
{
m_position_w = CollisionUtils::transformToWorld(m_cellObject->getCellProperty(),m_position_p);
}
}
break;
case AiLocationArchive::ALP_World:
{
Archive::get(source, m_position_w);
m_position_p = m_position_w;
}
break;
case AiLocationArchive::ALP_Object:
{
NetworkId objectId;
Archive::get(source, objectId);
setObject(NetworkIdManager::getObjectById(objectId));
}
break;
case AiLocationArchive::ALP_OffsetObject:
{
NetworkId objectId;
Archive::get(source, objectId);
Archive::get(source, m_offset_p);
setObject(NetworkIdManager::getObjectById(objectId));
}
break;
default:
WARNING(true, ("AiLocation::AiLocation(archive) received unknown data "
"type %d", static_cast<int>(package)));
break;
}
VALIDATE_LOCATION();
}
// ----------
void AiLocation::setObject ( Object const * object )
{
if(m_attached)
{
if (object == NULL)
{
clear();
return;
}
m_object = object;
m_objectId = m_object->getNetworkId();
m_position_p = m_object->getPosition_p();
m_position_w = m_object->getPosition_w();
m_cellObject = &(m_object->getParentCell()->getOwner());
VALIDATE_LOCATION();
}
}
// ----------------------------------------------------------------------
void AiLocation::detach ( void )
{
m_object = NULL;
m_objectId = NetworkId::cms_invalid;
m_attached = false;
}
// ----------------------------------------------------------------------
CellProperty const * AiLocation::getCell ( void ) const
{
return m_cellObject ? m_cellObject->getCellProperty() : NULL;
}
// ----------
NetworkId const & AiLocation::getCellId ( void ) const
{
CellProperty const * cell = getCell();
if(cell && (cell != CellProperty::getWorldCellProperty()))
{
return cell->getOwner().getNetworkId();
}
else
{
return NetworkId::cms_invalid;
}
}
// ----------------------------------------------------------------------
bool AiLocation::hasChanged ( void ) const
{
return m_hasChanged;
}
// ----------------------------------------------------------------------
Vector AiLocation::getPosition_p ( void ) const
{
if(m_cellObject.getPointer() == NULL)
{
WARNING(ConfigServerGame::getReportAiWarnings(),("AiLocation::getPosition_p - Locations's parent cell has disappeared\n"));
AiLocation * self = const_cast<AiLocation*>(this);
self->m_position_p = self->m_position_w;
self->m_cellObject = &(CellProperty::getWorldCellProperty()->getOwner());
VALIDATE_LOCATION();
}
return m_position_p;
}
// ----------
Vector AiLocation::getPosition_w ( void ) const
{
return m_position_w;
}
// ----------
Vector AiLocation::getPosition_p ( CellProperty const * relativeCell ) const
{
Vector pos_p = getPosition_p();
return CollisionUtils::transformToCell(getCell(),pos_p,relativeCell);
}
// ----------
void AiLocation::setPosition_p ( Vector const & position_p )
{
NAN_CHECK(position_p);
m_position_p = position_p;
m_position_w = CollisionUtils::transformToWorld(getCell(),position_p);
}
// ----------
void AiLocation::setPosition_w ( Vector const & position_w )
{
NAN_CHECK(position_w);
m_position_p = CollisionUtils::transformFromWorld(position_w,getCell());
m_position_w = position_w;
}
// ----------------------------------------------------------------------
Vector AiLocation::getOffsetPosition_p ( void ) const
{
Vector pos_p = getPosition_p();
Vector offset = m_relativeOffset ? m_object->rotate_o2p(m_offset_p) : m_offset_p;
return pos_p + offset;
}
// ----------
Vector AiLocation::getOffsetPosition_w ( void ) const
{
CellProperty const * cell = getCell();
if(cell)
{
return cell->getOwner().getTransform_o2w().rotateTranslate_l2p(getOffsetPosition_p());
}
else
{
return getOffsetPosition_p();
}
}
// ----------------------------------------------------------------------
void AiLocation::setOffset_p(Vector const & offset, bool relative)
{
m_offset_p = offset;
m_relativeOffset = relative;
m_hasChanged = true;
}
// ----------------------------------------------------------------------
float AiLocation::getRadius ( void ) const
{
return m_radius;
}
// ----------------------------------------------------------------------
void AiLocation::update ( void )
{
if(!m_attached) return;
if(!m_object)
{
// object this location refers to has disappeared
int id = static_cast<int>(m_objectId.getValue());
WARNING(ConfigServerGame::getReportAiWarnings(),("AiLocation::update - The object this location was attached (%d) to has disappeared\n",id));
m_attached = false;
m_valid = false;
return;
}
if(!m_cellObject)
{
WARNING(ConfigServerGame::getReportAiWarnings(),("AiLocation::getPosition_p - Location at (%f,%f,%f) - parent cell has disappeared\n",m_position_w.x,m_position_w.y,m_position_w.z));
m_position_p = m_position_w;
m_cellObject = &(CellProperty::getWorldCellProperty()->getOwner());
}
Vector const offset = m_relativeOffset ? m_object->rotate_o2p(m_offset_p) : m_offset_p;
Vector const newPosition_p = m_object->getPosition_p() + offset;
float const positionDeltaSquared = newPosition_p.magnitudeBetweenSquared(m_position_p);
CellProperty const * const objectCell = m_object->getParentCell();
if ((positionDeltaSquared > 0.00001f) || (getCell() != objectCell))
{
m_position_p = newPosition_p;
m_hasChanged = true;
m_cellObject = &(m_object->getParentCell()->getOwner());
m_position_w = CollisionUtils::transformToWorld(getCell(), m_position_p);
}
VALIDATE_LOCATION();
}
// ----------------------------------------------------------------------
void AiLocation::clear ( void )
{
// Note that this explicitly does _not_ clear m_objectId - if an
// AiLocation is detached from its object because the object was
// deleted, the behaviors will still need to know the now-invalid
// NetworkId so they can send it to the scripts.
m_valid = false;
m_attached = false;
m_object = NULL;
m_cellObject = NULL;
m_position_p = Vector::zero;
m_radius = 0.0f;
m_offset_p = Vector::zero;
m_relativeOffset = false;
m_hasChanged = true;
}
// ----------------------------------------------------------------------
bool AiLocation::isInWorldCell ( void ) const
{
return isValid() && ( (getCell() == NULL) || (getCell() == CellProperty::getWorldCellProperty()) );
}
// ----------------------------------------------------------------------
bool AiLocation::validate ( void ) const
{
NAN_CHECK(m_position_p);
NAN_CHECK(m_radius);
NAN_CHECK(m_offset_p);
TerrainObject * terrain = TerrainObject::getInstance();
if(terrain == NULL) return true;
float w = terrain->getMapWidthInMeters() / 2.0f;
bool valid = true;
valid &= (m_position_p.x <= w);
valid &= (m_position_p.x >= -w);
valid &= (m_position_p.z <= w);
valid &= (m_position_p.z >= -w);
float dist2 = getPosition_w().magnitudeSquared();
valid &= (dist2 >= 9.0f);
if(!valid)
{
DEBUG_WARNING(ConfigServerGame::getReportAiWarnings(),("AiLocation::validate - Location (%f,%f,%f) is OOW or too near the origin - terrain size %fx%f\n",m_position_p.x,m_position_p.y,m_position_p.z,w*2.0f,w*2.0f));
}
return valid;
}
// ----------------------------------------------------------------------
void AiLocation::getDebugInfo( std::string & outString ) const
{
Vector const & w = getPosition_w();
outString += FormattedString<1024>().sprintf("world location: %.2f, %.2f, %.2f\n", w.x, w.y, w.z);
}
// ----------------------------------------------------------------------
Vector const & AiLocation::getOffset_p() const
{
return m_offset_p;
}
@@ -0,0 +1,196 @@
// ======================================================================
//
// AiLocation.h
// Copyright 2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiLocation_H
#define INCLUDED_AiLocation_H
#include "sharedFoundation/NetworkId.h"
#include "sharedFoundation/Watcher.h"
#include "sharedMath/Vector.h"
#include "sharedObject/Object.h"
namespace Archive
{
class ByteStream;
class ReadIterator;
}
class CellProperty;
#ifdef _DEBUG
#define VALIDATE_LOCATION() validate()
#else
#define VALIDATE_LOCATION() NOP
#endif
// ======================================================================
class AiLocation
{
public:
AiLocation ( void );
AiLocation ( CellProperty const * cell, Vector const & point, float radius = 0.0f );
AiLocation ( NetworkId const & cellId, Vector const & point, float radius = 0.0f );
AiLocation ( Object const * target );
AiLocation ( NetworkId const & targetId );
AiLocation ( Object const * target, Vector const & offset, bool relativeOffset );
AiLocation ( NetworkId const & targetId, Vector const & offset, bool relativeOffset );
AiLocation ( AiLocation const & copy );
AiLocation ( Archive::ReadIterator & source );
~AiLocation();
static const AiLocation invalid;
AiLocation & operator = ( AiLocation const & copy );
void initialize ( void );
void pack ( Archive::ByteStream & target ) const;
void unpack ( Archive::ReadIterator & source );
// ----------
bool isValid ( void ) const;
bool hasChanged ( void ) const;
void setChanged ( bool changed );
Object const * getObject ( void ) const;
void setObject ( Object const * object );
void detach ( void );
NetworkId const & getObjectId ( void ) const;
CellProperty const * getCell ( void ) const;
NetworkId const & getCellId ( void ) const;
Vector getPosition_p ( void ) const;
Vector getPosition_w ( void ) const;
Vector getPosition_p ( CellProperty const * relativeCell ) const;
void setPosition_p ( Vector const & position_p );
void setPosition_w ( Vector const & position_w );
Vector getOffsetPosition_p ( void ) const;
Vector getOffsetPosition_w ( void ) const;
Vector const & getOffset_p() const;
void setOffset_p(Vector const & offset, bool relative);
float getRadius ( void ) const;
void setRadius ( float newRadius );
Vector getOffset ( void ) const;
void setOffset ( Vector const & newOffset );
bool getRelativeOffset ( void ) const;
void update ( void );
void clear ( void );
bool isInWorldCell ( void ) const;
bool isCuttable ( void ) const;
void setCuttable ( bool cuttable );
int getDebugId ( void ) const;
void getDebugInfo ( std::string & outString ) const;
// ----------
protected:
bool validate ( void ) const;
typedef ConstWatcher<Object> ObjectWatcher;
bool m_valid;
bool m_attached;
ObjectWatcher m_object;
NetworkId m_objectId;
ObjectWatcher m_cellObject;
Vector m_position_p;
Vector m_position_w;
float m_radius;
Vector m_offset_p;
bool m_relativeOffset;
bool m_hasChanged;
bool m_cuttable;
int m_debugId;
};
// ----------------------------------------------------------------------
inline bool AiLocation::isValid ( void ) const
{
return m_valid;
}
inline void AiLocation::setChanged( bool changed )
{
m_hasChanged = changed;
}
inline Object const * AiLocation::getObject ( void ) const
{
return m_object;
}
inline NetworkId const & AiLocation::getObjectId ( void ) const
{
return m_objectId;
}
inline void AiLocation::setRadius ( float newRadius )
{
m_radius = newRadius;
}
inline Vector AiLocation::getOffset ( void ) const
{
return m_offset_p;
}
inline void AiLocation::setOffset ( Vector const & newOffset )
{
m_offset_p = newOffset;
}
inline bool AiLocation::getRelativeOffset ( void ) const
{
return m_relativeOffset;
}
inline bool AiLocation::isCuttable ( void ) const
{
return m_cuttable;
}
inline void AiLocation::setCuttable ( bool cuttable )
{
m_cuttable = cuttable;
}
inline int AiLocation::getDebugId ( void ) const
{
return m_debugId;
}
// ======================================================================
#endif
@@ -0,0 +1,482 @@
// ======================================================================
//
// AiShipAttackTargetList.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipAttackTargetList.h"
#include "serverGame/AiShipController.h"
#include "serverGame/Client.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/CreatureObject.h"
#include "serverGame/PvpUpdateObserver.h"
#include "serverGame/ShipController.h"
#include "serverGame/ShipObject.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
#include "sharedNetworkMessages/UpdatePvpStatusMessage.h"
#include "sharedObject/NetworkIdManager.h"
#include <map>
// ======================================================================
//
// AiShipAttackTargetListNamespace
//
// ======================================================================
namespace AiShipAttackTargetListNamespace
{
typedef std::vector<NetworkId> PurgeList;
static PurgeList s_purgeList;
class CheapPvpIsEnemyObserver
{
public:
CheapPvpIsEnemyObserver(Object const * actor, Object const * target);
~CheapPvpIsEnemyObserver();
private:
CheapPvpIsEnemyObserver();
CheapPvpIsEnemyObserver(CheapPvpIsEnemyObserver const & copy);
CheapPvpIsEnemyObserver & operator = (CheapPvpIsEnemyObserver const & copy);
private:
ConstWatcher<TangibleObject> m_actor;
ConstWatcher<TangibleObject> m_target;
bool m_targetIsEnemy;
};
}
// ======================================================================
AiShipAttackTargetListNamespace::CheapPvpIsEnemyObserver::CheapPvpIsEnemyObserver(Object const * const actor, Object const * const target)
: m_actor(0)
, m_target(0)
, m_targetIsEnemy(false)
{
ServerObject const * const actorSO = (actor != 0) ? actor->asServerObject() : 0;
m_actor = (actorSO != 0) ? actorSO->asTangibleObject() : 0;
ServerObject const * const targetSO = (target != 0) ? target->asServerObject() : 0;
m_target = (targetSO != 0) ? targetSO->asTangibleObject() : 0;
if ((m_actor != 0) && (m_target != 0))
{
m_targetIsEnemy = Pvp::isEnemy(*m_actor, *m_target);
}
}
// ----------------------------------------------------------------------
AiShipAttackTargetListNamespace::CheapPvpIsEnemyObserver::~CheapPvpIsEnemyObserver()
{
if ((m_actor != 0) && (m_target != 0))
{
if (m_targetIsEnemy != Pvp::isEnemy(*m_actor, *m_target))
{
typedef std::set<Client const *> AuthClients;
AuthClients authClients;
m_target->getAuthClients(authClients);
AuthClients::const_iterator ii = authClients.begin();
AuthClients::const_iterator iiEnd = authClients.end();
for (; ii != iiEnd; ++ii)
{
Client const * const client = *ii;
uint32 flags, factionId;
Pvp::getClientVisibleStatus(*client, *m_actor, flags, factionId);
UpdatePvpStatusMessage const statusMessage(m_actor->getNetworkId(), flags, factionId);
client->send(statusMessage, true);
PvpUpdateObserver::updatePvpStatusCache(client, *m_actor, flags, factionId);
}
}
}
}
using namespace AiShipAttackTargetListNamespace;
// ======================================================================
//
// AiShipAttackTargetList::AiShipAttackTargetEntry
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipAttackTargetList::AiShipAttackTargetEntry::AiShipAttackTargetEntry(float const initialDamage)
: m_damage(initialDamage)
, m_lastDamageTime(Os::getRealSystemTime())
{
}
// ======================================================================
//
// AiShipAttackTargetList
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipAttackTargetList::AiShipAttackTargetList(ShipObject * const owner)
: m_owner(NON_NULL(owner))
, m_targetList(new TargetList)
, m_primaryTarget(CachedNetworkId::cms_cachedInvalid)
, m_primaryTargetDamage(0.0f)
{
}
// ----------------------------------------------------------------------
AiShipAttackTargetList::~AiShipAttackTargetList()
{
// Notify all the targeted ships that they are no longer being targeted
while (!m_targetList->empty())
{
NetworkId const & unit = m_targetList->begin()->first;
bool const inDestructorHack = true;
if (!remove(unit, inDestructorHack))
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::~AiShipAttackTargetList() ERROR: Unable to remove the unit(%s) from the target list.", unit.getValueString().c_str()));
break;
}
}
delete m_targetList;
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::add(ShipObject & unit, float const damage)
{
#ifdef _DEBUG
AiShipController * const ownerAiShipController = AiShipController::asAiShipController(m_owner->getController());
if (ownerAiShipController != NULL)
{
if (!ownerAiShipController->isValidTarget(unit))
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::add() ERROR: Adding an invalid attack target to (%s) which has an exclusive aggro list and this unit(%s) is not in it.", m_owner->getDebugInformation().c_str(), unit.getDebugInformation().c_str()));
return;
}
}
#endif // _DEBUG
CheapPvpIsEnemyObserver observer(m_owner, &unit);
// Add damage to myself
float attackingUnitDamageTotal = damage;
TargetList::iterator iterTargetList = m_targetList->find(CachedNetworkId(unit));
if (iterTargetList != m_targetList->end())
{
iterTargetList->second.m_damage += damage;
attackingUnitDamageTotal = iterTargetList->second.m_damage;
iterTargetList->second.m_lastDamageTime = Os::getRealSystemTime();
}
else
{
AiShipAttackTargetEntry entry(damage);
IGNORE_RETURN(m_targetList->insert(std::make_pair(CachedNetworkId(unit.getNetworkId()), entry)));
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::add() unit(%s) attackingUnit(%s) damage(%.f) ADDING NEW ATTACK TARGET", m_owner->getNetworkId().getValueString().c_str(), unit.getNetworkId().getValueString().c_str(), damage));
}
m_owner->getController()->asShipController()->onAttackTargetChanged(unit.getNetworkId());
// See if this unit is the new primary attack target, and it is not the current primary attack target
if (attackingUnitDamageTotal > m_primaryTargetDamage)
{
setNewPrimaryTarget(CachedNetworkId(unit), attackingUnitDamageTotal);
}
// Notify the unit that attacked me that I am targeting them
ShipController * const attackingUnitShipController = unit.getController()->asShipController();
if (attackingUnitShipController != NULL)
{
attackingUnitShipController->addAiTargetingMe(m_owner->getNetworkId());
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::add() ERROR: owner(%s) Why does this unit(%s) not have a ShipController?", m_owner->getNetworkId().getValueString().c_str(), unit.getNetworkId().getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
bool AiShipAttackTargetList::remove(NetworkId const & unit, bool const inDestructorHack)
{
DEBUG_FATAL((unit == NetworkId::cms_invalid), ("Removing a NULL unit"));
bool result = false;
// Remove the specified unit
TargetList::iterator iterTargetList = m_targetList->find(CachedNetworkId(unit));
if (iterTargetList != m_targetList->end())
{
Object * const object = NetworkIdManager::getObjectById(unit);
CheapPvpIsEnemyObserver observer(m_owner, object);
result = true;
m_targetList->erase(iterTargetList);
m_owner->getController()->asShipController()->onAttackTargetLost(unit);
// Tell this unit that we are no longer targeting it
if (object != NULL)
{
ShipController * const shipController = object->getController()->asShipController();
if (shipController != NULL)
{
shipController->removeAiTargetingMe(m_owner->getNetworkId());
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::remove() owner(%s) ERROR: Why does this unit(%s) not have an ShipController?", m_owner->getDebugInformation().c_str(), unit.getValueString().c_str()));
}
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::remove() owner(%s) ERROR: The unit(%s) did not resolve to an Object.", m_owner->getDebugInformation().c_str(), unit.getValueString().c_str()));
}
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::remove() owner(%s) ERROR: Unable to find the unit(%s) in the attack target list.", m_owner->getDebugInformation().c_str(), unit.getValueString().c_str()));
}
// If the unit being removed was the primary attack target, find a new primary attack target
if ( !inDestructorHack
&& (m_primaryTarget == unit))
{
findNewPrimaryTarget();
}
return result;
}
// ----------------------------------------------------------------------
CachedNetworkId const & AiShipAttackTargetList::getPrimaryTarget() const
{
return m_primaryTarget;
}
// ----------------------------------------------------------------------
AiShipAttackTargetList::TargetList const & AiShipAttackTargetList::getUnSortedTargetList() const
{
return *m_targetList;
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::getSortedTargetList(SortedTargetList & destTargetList) const
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::getSortedTargetList() owner(%s) m_targetList->size(%u)", m_owner->getNetworkId().getValueString().c_str(), m_targetList->size()));
destTargetList.clear();
// Sort the targets based on the most damage inflicted
if (!m_targetList->empty())
{
// Sort the results
typedef std::multimap<float, std::pair<CachedNetworkId, AiShipAttackTargetEntry> > SortedResults;
SortedResults sortedResults;
TargetList::const_iterator iterTargetList = m_targetList->begin();
for (; iterTargetList != m_targetList->end(); ++iterTargetList)
{
IGNORE_RETURN(sortedResults.insert(std::make_pair(iterTargetList->second.m_damage, std::make_pair(iterTargetList->first, iterTargetList->second))));
}
// Save the sorted results
destTargetList.reserve(sortedResults.size());
SortedResults::reverse_iterator iterSortedResults = sortedResults.rbegin();
for (; iterSortedResults != sortedResults.rend(); ++iterSortedResults)
{
destTargetList.push_back(std::make_pair(iterSortedResults->second.first, iterSortedResults->second.second));
}
}
}
// ----------------------------------------------------------------------
bool AiShipAttackTargetList::isEmpty() const
{
return getUnSortedTargetList().empty();
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::purge(time_t const maxAge)
{
// Remove targets that caused damaged too long ago
if (!isEmpty())
{
time_t const systemTime = Os::getRealSystemTime();
TargetList::iterator iterTargetList = m_targetList->begin();
s_purgeList.clear();
for (; iterTargetList != m_targetList->end(); ++iterTargetList)
{
NOT_NULL(iterTargetList->first.getObject());
time_t const age = systemTime - iterTargetList->second.m_lastDamageTime;
if (age >= maxAge)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::purge() target(%s) age(%u) maxAge(%u) m_targetList->size(%u)", iterTargetList->first.getValueString().c_str(), age, maxAge, m_targetList->size() - 1));
NetworkId const lostUnit(iterTargetList->first);
s_purgeList.push_back(lostUnit);
}
}
PurgeList::const_iterator iterPurgeList = s_purgeList.begin();
for (; iterPurgeList != s_purgeList.end(); ++iterPurgeList)
{
NetworkId const & unit = (*iterPurgeList);
remove(unit);
}
}
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::findNewPrimaryTarget()
{
CachedNetworkId newPrimaryTarget;
float newPrimaryTargetDamage = 0.0f;
// Walk all the attack targets and get the one with the most damage inflicted
TargetList::const_iterator iterTargetList = m_targetList->begin();
for (; iterTargetList != m_targetList->end(); ++iterTargetList)
{
NOT_NULL(iterTargetList->first.getObject());
if ( (iterTargetList->second.m_damage > m_primaryTargetDamage)
|| (newPrimaryTarget == CachedNetworkId::cms_cachedInvalid))
{
newPrimaryTarget = iterTargetList->first;
newPrimaryTargetDamage = iterTargetList->second.m_damage;
}
}
setNewPrimaryTarget(newPrimaryTarget, newPrimaryTargetDamage);
#ifdef _DEBUG
if (m_targetList->empty())
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::findNewPrimaryTarget() m_owner(%s) NO TARGET (Empty target list)", m_owner->getNetworkId().getValueString().c_str()));
}
else
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::findNewPrimaryTarget() m_owner(%s) m_targetList->size(%u) primaryTarget(%s) damage(%f)", m_owner->getNetworkId().getValueString().c_str(), m_targetList->size(), m_primaryTarget.getValueString().c_str(), m_primaryTargetDamage));
}
// We should only have ship objects in our target list
if (m_primaryTarget.getObject() != NULL)
{
ServerObject * const targetServerObject = m_primaryTarget.getObject()->asServerObject();
ShipObject * const targetShipObject = (targetServerObject != NULL) ? targetServerObject->asShipObject() : NULL;
if (targetShipObject == NULL)
{
DEBUG_WARNING(true, ("debug_ai: AiShipAttackTargetList::findNewPrimaryTarget() ERROR: How did we get a target that is not a ShipObject (%s)", m_primaryTarget.getObject()->getDebugInformation().c_str()));
}
}
#endif // _DEBUG
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::clear()
{
if (!isEmpty())
{
purge(0);
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::clear() m_owner(%s) m_targetList->size(%u) primaryTarget(%s)", m_owner->getNetworkId().getValueString().c_str(), m_targetList->size(), m_primaryTarget.getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::setNewPrimaryTarget(CachedNetworkId const & newPrimaryTarget, float const damage)
{
m_primaryTargetDamage = damage;
if (m_primaryTarget != newPrimaryTarget)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipAttackTargetList::setNewPrimaryTarget() m_owner(%s) newPrimaryTarge(%s) damage(%.2f) m_targetList->size(%u)", m_owner->getNetworkId().getValueString().c_str(), newPrimaryTarget.getValueString().c_str(), damage, m_targetList->size()));
m_primaryTarget = newPrimaryTarget;
m_owner->setPilotLookAtTarget(newPrimaryTarget);
}
}
// ----------------------------------------------------------------------
void AiShipAttackTargetList::verify()
{
// If the owner of the target list has exclusive aggros, then we might need to purge some of the targets from the list
AiShipController * const ownerAiShipController = AiShipController::asAiShipController(m_owner->getController());
if (ownerAiShipController != NULL)
{
if (ownerAiShipController->hasExclusiveAggros())
{
// We have exclusive aggros, remove any invalid targets
TargetList::iterator iterTargetList = m_targetList->begin();
s_purgeList.clear();
for (; iterTargetList != m_targetList->end(); ++iterTargetList)
{
ShipObject * const unitShipObject = ShipObject::asShipObject(iterTargetList->first.getObject());
CreatureObject const * const unitPilot = (unitShipObject != NULL) ? unitShipObject->getPilot() : NULL;
if ( (unitPilot == NULL)
|| !ownerAiShipController->isExclusiveAggro(*unitPilot))
{
s_purgeList.push_back(unitShipObject->getNetworkId());
}
}
PurgeList::const_iterator iterPurgeList = s_purgeList.begin();
for (; iterPurgeList != s_purgeList.end(); ++iterPurgeList)
{
NetworkId const & unit = (*iterPurgeList);
remove(unit);
}
s_purgeList.clear();
}
}
}
// ======================================================================
@@ -0,0 +1,76 @@
// ======================================================================
//
// AiShipAttackTargetList.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipAttackTargetList_H
#define INCLUDED_AiShipAttackTargetList_H
#include "sharedObject/CachedNetworkId.h"
class NetworkId;
class ShipObject;
// ======================================================================
class AiShipAttackTargetList
{
public:
class AiShipAttackTargetEntry
{
public:
AiShipAttackTargetEntry(float const initialDamage);
float m_damage;
time_t m_lastDamageTime;
private:
// Disabled
AiShipAttackTargetEntry();
};
typedef stdmap<CachedNetworkId, AiShipAttackTargetEntry>::fwd TargetList;
typedef stdvector<std::pair<CachedNetworkId, AiShipAttackTargetEntry> >::fwd SortedTargetList;
public:
AiShipAttackTargetList(ShipObject * const owner);
~AiShipAttackTargetList();
bool isEmpty() const;
void add(ShipObject & unit, float const damage);
bool remove(NetworkId const & unit, bool const inDestructorHack = false);
void purge(time_t const maxAge);
void clear();
void verify();
CachedNetworkId const & getPrimaryTarget() const;
TargetList const & getUnSortedTargetList() const; // Faster
void getSortedTargetList(SortedTargetList & destTargetList) const; // Slower, don't call every frame
private:
void findNewPrimaryTarget();
void setNewPrimaryTarget(CachedNetworkId const & newPrimaryTarget, float const damage);
ShipObject * const m_owner;
TargetList * const m_targetList;
CachedNetworkId m_primaryTarget;
float m_primaryTargetDamage;
// Disabled
AiShipAttackTargetList(AiShipAttackTargetList const &);
AiShipAttackTargetList &operator =(AiShipAttackTargetList const &);
};
// ======================================================================
#endif // INCLUDED_AiShipAttackTargetList_H
@@ -0,0 +1,126 @@
// ======================================================================
//
// AiShipBehaviorAttack.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorAttack.h"
#include "serverGame/AiShipAttackTargetList.h"
#include "serverGame/AiShipController.h"
#include "serverGame/AiShipPilotData.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipObject.h"
#include "serverGame/SpaceSquad.h"
#include "serverGame/SpaceAttackSquad.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedGame/AiDebugString.h"
#include "sharedGame/SharedObjectTemplate.h"
#include "sharedLog/Log.h"
#include "sharedObject/NetworkIdManager.h"
// ======================================================================
AiShipBehaviorAttack::AiShipBehaviorAttack(AiShipController & aiShipController)
: AiShipBehaviorBase(aiShipController)
, m_leashRadius(aiShipController.getPilotData()->m_leashRadius)
, m_damageTaken(false)
{
}
// ----------------------------------------------------------------------
AiShipBehaviorAttack::AiShipBehaviorAttack(AiShipBehaviorAttack const & rhs)
: AiShipBehaviorBase(rhs)
, m_leashRadius(rhs.m_leashRadius)
, m_damageTaken(rhs.m_damageTaken)
{
}
// ----------------------------------------------------------------------
AiShipBehaviorAttack::~AiShipBehaviorAttack()
{
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttack::alter(float const /*deltaTime*/)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorAttack::alter");
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttack::setLeashRadius(float const radius)
{
m_leashRadius = radius;
}
// ----------------------------------------------------------------------
float AiShipBehaviorAttack::getLeashRadius() const
{
return m_leashRadius;
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttack::isWithinLeashDistance() const
{
Vector const & ownerPosition_w = getAiShipController().getOwnerPosition_w();
Vector const & leashAnchorPosition_w = getAiShipController().getSquad().getLeashAnchorPosition_w();
float const distanceFromLeashAnchorPositionSquared = ownerPosition_w.magnitudeBetweenSquared(leashAnchorPosition_w);
return (distanceFromLeashAnchorPositionSquared < sqr(getLeashRadius()));
}
// ----------------------------------------------------------------------
float AiShipBehaviorAttack::getPercentWithinLeashDistance() const
{
DEBUG_WARNING((getLeashRadius() <= 0.0f), ("AiShipBehaviorAttack::getPercentWithinLeashDistance() The leash radius(%f) must be > 0", getLeashRadius()));
Vector const & ownerPosition_w = getAiShipController().getOwnerPosition_w();
Vector const & leashAnchorPosition_w = getAiShipController().getSquad().getLeashAnchorPosition_w();
// == 1 means the unit is on the leash anchor position
// == 0 means the unit is on the shell of the leash sphere
// < 0 means the unit is outside the leash sphere
float const result = (1.0f - (leashAnchorPosition_w.magnitudeBetween(ownerPosition_w) / std::max(1.0f, getLeashRadius())));
return result;
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
void AiShipBehaviorAttack::addDebug(AiDebugString & aiDebugString)
{
if (getAiShipController().isAttackSquadLeader())
{
// Show the squad leader look at target
NetworkId const & lookAtTarget = m_aiShipController.getShipOwner()->getPilotLookAtTarget();
if (lookAtTarget != NetworkId::cms_invalid)
{
aiDebugString.addLineToObject(lookAtTarget, PackedRgb::solidRed);
}
// Show the squad leader leash position
aiDebugString.addLineToPosition(m_aiShipController.getSquad().getLeashAnchorPosition_w(), PackedRgb::solidGreen);
// Show the squad leader leash radius
//aiDebugString.addCircle(m_aiShipController.getLeashAnchorPosition_w(), getLeashRadius(), PackedRgb::solidGreen);
}
}
#endif // _DEBUG
// ======================================================================
@@ -0,0 +1,54 @@
// ======================================================================
//
// AiShipBehaviorAttack.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttack_H
#define INCLUDED_AiShipBehaviorAttack_H
#include "serverGame/AiShipBehaviorBase.h"
#include "sharedFoundation/Watcher.h"
class AiDebugString;
class NetworkId;
class Object;
class ShipObject;
// ======================================================================
class AiShipBehaviorAttack : public AiShipBehaviorBase
{
public:
explicit AiShipBehaviorAttack(AiShipController & aiShipController);
AiShipBehaviorAttack(AiShipBehaviorAttack const & rhs);
virtual ~AiShipBehaviorAttack() = 0;
virtual void alter(float time);
void setLeashRadius(float const radius);
float getLeashRadius() const;
bool isWithinLeashDistance() const;
float getPercentWithinLeashDistance() const;
#ifdef _DEBUG
virtual void addDebug(AiDebugString & aiDebugString);
#endif // _DEBUG
private:
float m_leashRadius;
bool m_damageTaken;
// Disabled
AiShipBehaviorAttack();
AiShipBehaviorAttack &operator =(AiShipBehaviorAttack const &);
};
// ======================================================================
#endif //INCLUDED_AiShipBehaviorAttack_H
@@ -0,0 +1,366 @@
// ======================================================================
//
// AiShipBehaviorAttackBomber.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorAttackBomber.h"
#include "serverGame/AiShipController.h"
#include "serverGame/AiShipPilotData.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipObject.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedGame/AiDebugString.h"
#include "sharedGame/ShipComponentWeaponManager.h"
#include "sharedLog/Log.h"
#include "sharedObject/NetworkIdManager.h"
// ======================================================================
namespace AiShipBehaviorAttackBomber_namespace
{
float const ms_breakOffDistanceSquared = sqr(200.0f);
float const ms_evadeOffsetMax = 200.0f; // constant for now, TODO: hook this up to the pilot type data table
struct TargetShipData
{
TargetShipData();
typedef std::map<ShipChassisSlotType::Type, int> BombersPerComponentType;
int m_totalBombers;
BombersPerComponentType m_bombersPerComponent;
};
typedef std::map<NetworkId, TargetShipData> TargetShipsType;
TargetShipsType ms_targetShips;
}
using namespace AiShipBehaviorAttackBomber_namespace;
// ======================================================================
AiShipBehaviorAttackBomber::AiShipBehaviorAttackBomber(AiShipController & aiShipController) :
AiShipBehaviorAttack(aiShipController),
m_attackStage(AS_attack),
m_targetId(NetworkId::cms_invalid),
m_targetComponentSlot(ShipChassisSlotType::SCST_invalid),
m_targetComponentPosition_o(Vector::zero),
m_evadePosition_o(Vector::zero),
m_evadeDistanceSquared(0.0f),
m_evadeOffset(Vector::zero),
m_evadeChangeDirectionTimer(0.5f),
m_missilesFired(0)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorAttackBomber::AiShipBehaviorAttackBomber() unit(%s)", (aiShipController.getOwner() != NULL) ? aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner"));
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackBomber::AiShipBehaviorAttackBomber(AiShipBehaviorAttack const & sourceBehavior) :
AiShipBehaviorAttack(sourceBehavior),
m_attackStage(AS_attack),
m_targetId(NetworkId::cms_invalid),
m_targetComponentSlot(ShipChassisSlotType::SCST_invalid),
m_targetComponentPosition_o(Vector::zero),
m_evadePosition_o(Vector::zero),
m_evadeDistanceSquared(0.0f),
m_evadeOffset(Vector::zero),
m_evadeChangeDirectionTimer(0.5f),
m_missilesFired(0)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorAttackBomber::AiShipBehaviorAttackBomber(AiShipBehaviorAttack &) unit(%s)", (m_aiShipController.getOwner() != NULL) ? m_aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner"));
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackBomber::~AiShipBehaviorAttackBomber()
{
changeTargetObject(NetworkId::cms_invalid);
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackBomber::alter(float const deltaTime)
{
AiShipBehaviorAttack::alter(deltaTime);
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorAttackBomber::alter");
NetworkId const & newTargetId = getAiShipController().getPrimaryAttackTarget();
if (newTargetId != m_targetId)
{
changeTargetObject(newTargetId);
}
if (getTargetCapitalShip())
{
if (m_targetComponentSlot == ShipChassisSlotType::SCST_invalid)
selectTargetComponent();
if (m_targetComponentSlot != ShipChassisSlotType::SCST_invalid)
{
switch(m_attackStage)
{
case AS_evade:
doEvade(deltaTime);
break;
case AS_attack:
doAttackRun(deltaTime);
break;
default:
break;
}
}
}
else
{
// switch to a fighter attack behavior
m_aiShipController.switchToFighterAttack();
}
}
// ----------------------------------------------------------------------
/**
* Helper function to pick a component on the targeted capital ship to attack.
* Note: success is not guaranteed. A component may not be selected after
* this function returns
*/
void AiShipBehaviorAttackBomber::selectTargetComponent()
{
ShipObject const * const targetShipObject = getTargetCapitalShip();
if (targetShipObject)
{
Vector const position_w=NON_NULL(m_aiShipController.getShipOwner())->getPosition_w();
float const evadeDistance = targetShipObject->getApproximateAttackRange();
m_evadeDistanceSquared = sqr(evadeDistance);
ShipChassisSlotType::Type newTargetComponentSlot = ShipChassisSlotType::SCST_invalid;
TargetShipData & targetShipData = ms_targetShips[targetShipObject->getNetworkId()];
float closestSoFar = 0;
int fewestBombersSoFar = 0;
std::vector<Transform> transforms;
for (int chassisSlot = ShipChassisSlotType::SCST_first; chassisSlot < ShipChassisSlotType::SCST_num_types; ++chassisSlot)
{
if (targetShipObject->isValidTargetableSlot(static_cast<ShipChassisSlotType::Type>(chassisSlot)))
{
targetShipObject->findTransformsForComponent(chassisSlot, transforms);
for (std::vector<Transform>::const_iterator i=transforms.begin(); i!=transforms.end(); ++i)
{
// pick the component whose "evade" position, i.e. the start position for the attack run,
// is closest to where we are now.
// If coordinating with other bombers, prefer the components that have the fewest bombers
// already attacking them.
Vector const evadePosition_o = i->getPosition_p() + (i->getLocalFrameJ_p() * evadeDistance * 1.5f);
Vector const evadePosition_w = targetShipObject->rotateTranslate_o2w(evadePosition_o);
float const distanceSquared = (evadePosition_w - position_w).magnitudeSquared();
bool preferThisOne = false;
if (closestSoFar == 0)
preferThisOne = true;
if (targetShipData.m_bombersPerComponent[static_cast<ShipChassisSlotType::Type>(chassisSlot)] < fewestBombersSoFar)
preferThisOne = true;
if (targetShipData.m_bombersPerComponent[static_cast<ShipChassisSlotType::Type>(chassisSlot)] == fewestBombersSoFar &&
distanceSquared < closestSoFar)
preferThisOne = true;
if (preferThisOne)
{
closestSoFar = distanceSquared;
fewestBombersSoFar = targetShipData.m_bombersPerComponent[static_cast<ShipChassisSlotType::Type>(chassisSlot)];
m_targetComponentPosition_o = i->getPosition_p();
m_evadePosition_o = evadePosition_o;
newTargetComponentSlot = static_cast<ShipChassisSlotType::Type>(chassisSlot);
}
}
}
}
if (newTargetComponentSlot != ShipChassisSlotType::SCST_invalid)
{
DEBUG_REPORT_LOG(true,("Ship %s targetting slot %i\n",m_aiShipController.getShipOwner()->getNetworkId().getValueString().c_str(),newTargetComponentSlot));
changeTargetComponentSlot(newTargetComponentSlot);
}
}
}
// ----------------------------------------------------------------------
/**
* Fly towards a point in space near the capital ship but out of range of
* its weapons
*/
void AiShipBehaviorAttackBomber::doEvade(float const deltaTime)
{
ShipObject * const ownerShipObject = NON_NULL(m_aiShipController.getShipOwner());
ownerShipObject->setBoosterActive(true);
if (m_evadeChangeDirectionTimer.updateZero(deltaTime))
{
m_evadeOffset = Vector (Random::randomReal(-ms_evadeOffsetMax,ms_evadeOffsetMax),
Random::randomReal(-ms_evadeOffsetMax,ms_evadeOffsetMax),
Random::randomReal(-ms_evadeOffsetMax,ms_evadeOffsetMax));
}
Vector const goalPosition_w = NON_NULL(getTargetCapitalShip())->rotateTranslate_o2w(m_evadePosition_o) + m_evadeOffset;
float const throttle = 1.0f;
m_aiShipController.moveTo(goalPosition_w, throttle, deltaTime);
if ((getTargetCapitalShip()->getPosition_w() - NON_NULL(m_aiShipController.getShipOwner())->getPosition_w()).magnitudeSquared() > m_evadeDistanceSquared)
m_attackStage = AS_attack;
}
// ----------------------------------------------------------------------
/**
* Make a run at the selected component of the capital ship. Fire missiles &
* guns when in range.
*/
void AiShipBehaviorAttackBomber::doAttackRun(float const deltaTime)
{
ShipObject const * const targetShipObject = NON_NULL(getTargetCapitalShip());
ShipObject * const ownerShipObject = NON_NULL(m_aiShipController.getShipOwner());
AiShipPilotData const * pilotData = m_aiShipController.getPilotData();
Vector const goalPosition_w = targetShipObject->rotateTranslate_o2w(m_targetComponentPosition_o);
Vector const goalPosition_o = ownerShipObject->rotateTranslate_w2o(goalPosition_w); // target in the space of the owner ship
// Move & do avoidance if necessary
float const throttle = 1.0f;
m_aiShipController.moveTo(goalPosition_w, throttle, deltaTime);
// Fire weapons if possible
Vector normalizedTargetPosition_o(goalPosition_o);
if (normalizedTargetPosition_o.approximateNormalize() && (acos(normalizedTargetPosition_o.dot(Vector::unitZ)) < pilotData->m_projectileFireAngle))
{
for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex)
{
if (!ownerShipObject->isTurret(weaponIndex))
{
if (goalPosition_o.magnitudeSquared() < sqr(ownerShipObject->getWeaponRange(weaponIndex)))
{
ShipChassisSlotType::Type const chassisSlot = static_cast<ShipChassisSlotType::Type>(static_cast<int>(ShipChassisSlotType::SCST_weapon_0) + weaponIndex);
if (ownerShipObject->isSlotInstalled(chassisSlot))
{
if (ownerShipObject->canFireShot(weaponIndex))
{
if (ShipComponentWeaponManager::isMissile(ownerShipObject->getComponentCrc(chassisSlot)))
++m_missilesFired;
ownerShipObject->fireShotNonTurretServer(weaponIndex, targetShipObject->getNetworkId(), m_targetComponentSlot);
}
}
}
}
}
}
// Don't fire booster while on attack run (more time to launch missiles & fire guns)
ownerShipObject->setBoosterActive(false);
// Check for state changes
if (!targetShipObject->isValidTargetableSlot(static_cast<ShipChassisSlotType::Type>(m_targetComponentSlot)))
changeTargetComponentSlot(ShipChassisSlotType::SCST_invalid);
if (((ownerShipObject->getPosition_w() - goalPosition_w).magnitudeSquared() < ms_breakOffDistanceSquared) || m_missilesFired >= pilotData->m_bomberMissilesPerBombingRun)
{
m_attackStage = AS_evade;
m_missilesFired = 0;
}
}
// ----------------------------------------------------------------------
/**
* Returns a pointer to the target object, if it is a capital ship
*/
ShipObject const * AiShipBehaviorAttackBomber::getTargetCapitalShip() const
{
ShipObject const * const targetShipObject = getAiShipController().getPrimaryAttackTargetShipObject();
if (targetShipObject && targetShipObject->isCapitalShip())
{
return targetShipObject;
}
return NULL;
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackBomber::changeTargetObject(NetworkId const & newTarget)
{
changeTargetComponentSlot(ShipChassisSlotType::SCST_invalid);
if (m_targetId != NetworkId::cms_invalid)
{
TargetShipData & data = ms_targetShips[m_targetId];
if (--(data.m_totalBombers) <= 0)
IGNORE_RETURN(ms_targetShips.erase(m_targetId));
}
if (newTarget != NetworkId::cms_invalid)
{
TargetShipData & data = ms_targetShips[newTarget];
++(data.m_totalBombers);
}
m_targetId = newTarget;
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackBomber::changeTargetComponentSlot(ShipChassisSlotType::Type newTarget)
{
if (m_targetId != NetworkId::cms_invalid)
{
TargetShipsType::iterator data=ms_targetShips.find(m_targetId);
DEBUG_FATAL(data == ms_targetShips.end(),("Programmer bug: changing target slot, but target %s is not in ms_targetShips. It should have already been added",m_targetId.getValueString().c_str()));
if (m_targetComponentSlot != ShipChassisSlotType::SCST_invalid)
--(data->second.m_bombersPerComponent[m_targetComponentSlot]);
if (newTarget != ShipChassisSlotType::SCST_invalid)
++(data->second.m_bombersPerComponent[newTarget]);
}
DEBUG_FATAL(newTarget < ShipChassisSlotType::SCST_first || newTarget > ShipChassisSlotType::SCST_num_types,("newTarget out of range"));
m_targetComponentSlot = newTarget;
}
// ----------------------------------------------------------------------
TargetShipData::TargetShipData() :
m_totalBombers(0),
m_bombersPerComponent()
{
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
void AiShipBehaviorAttackBomber::addDebug(AiDebugString & aiDebugString)
{
AiShipBehaviorAttack::addDebug(aiDebugString);
// Show the current maneuver
{
char const * const text = FormattedString<512>().sprintf("BOMBER\n");
aiDebugString.addText(text, PackedRgb::solidCyan);
}
}
#endif // _DEBUG
// ======================================================================
@@ -0,0 +1,66 @@
// ======================================================================
//
// AiShipBehaviorAttackBomber.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttackBomber_H
#define INCLUDED_AiShipBehaviorAttackBomber_H
#include "sharedFoundation/Timer.h"
#include "serverGame/AiShipBehaviorAttack.h"
#include "sharedFoundation/NetworkId.h"
#include "sharedGame/ShipChassisSlotType.h"
#include "sharedMath/Vector.h"
class AiDebugString;
class AiShipController;
class ShipObject;
// ======================================================================
class AiShipBehaviorAttackBomber : public AiShipBehaviorAttack
{
public:
explicit AiShipBehaviorAttackBomber(AiShipController & aiShipController);
explicit AiShipBehaviorAttackBomber(AiShipBehaviorAttack const & sourceBehavior);
virtual ~AiShipBehaviorAttackBomber();
virtual void alter(float time);
void addDebug(AiDebugString & aiDebugString);
private:
enum AttackStage {AS_attack, AS_evade};
private:
void selectTargetComponent();
void doEvade(float const deltaTime);
void doAttackRun(float const deltaTime);
ShipObject const * getTargetCapitalShip() const;
void changeTargetObject(NetworkId const & newTarget);
void changeTargetComponentSlot(ShipChassisSlotType::Type newTarget);
private:
AttackStage m_attackStage;
NetworkId m_targetId;
ShipChassisSlotType::Type m_targetComponentSlot;
Vector m_targetComponentPosition_o; // in the space of the target ship
Vector m_evadePosition_o; // in the space of the target ship
float m_evadeDistanceSquared;
Vector m_evadeOffset;
Timer m_evadeChangeDirectionTimer;
int m_missilesFired;
private:
// Disabled
AiShipBehaviorAttackBomber();
AiShipBehaviorAttackBomber(AiShipBehaviorAttackBomber const &);
AiShipBehaviorAttackBomber &operator =(AiShipBehaviorAttackBomber const &);
};
// ======================================================================
#endif //INCLUDED_AiShipBehaviorAttackBomber_H
@@ -0,0 +1,38 @@
// ======================================================================
//
// AiShipBehaviorAttackCapitalShip.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorAttackCapitalShip.h"
#include "serverGame/AiShipController.h"
#include "serverGame/ConfigServerGame.h"
#include "sharedDebug/Profiler.h"
#include "sharedLog/Log.h"
// ======================================================================
AiShipBehaviorAttackCapitalShip::AiShipBehaviorAttackCapitalShip(AiShipController & aiShipController)
: AiShipBehaviorAttack(aiShipController)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorAttackCapitalShip::AiShipBehaviorAttackCapitalShip() unit(%s)", (m_aiShipController.getOwner() != NULL) ? m_aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner"));
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackCapitalShip::~AiShipBehaviorAttackCapitalShip()
{
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackCapitalShip::alter(float const /*deltaSeconds*/)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorAttackCapitalShip::alter");
}
// ======================================================================
@@ -0,0 +1,37 @@
// ======================================================================
//
// AiShipBehaviorAttackCapitalShip.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttackCapitalShip_H
#define INCLUDED_AiShipBehaviorAttackCapitalShip_H
#include "serverGame/AiShipBehaviorAttack.h"
#include "sharedFoundation/Timer.h"
class NetworkId;
// ======================================================================
class AiShipBehaviorAttackCapitalShip : public AiShipBehaviorAttack
{
public:
explicit AiShipBehaviorAttackCapitalShip(AiShipController & aiShipController);
virtual ~AiShipBehaviorAttackCapitalShip();
virtual void alter(float deltaSeconds);
private:
// Disabled
AiShipBehaviorAttackCapitalShip();
AiShipBehaviorAttackCapitalShip(AiShipBehaviorAttackCapitalShip const &);
AiShipBehaviorAttackCapitalShip &operator =(AiShipBehaviorAttackCapitalShip const &);
};
// ======================================================================
#endif //INCLUDED_AiShipBehaviorAttackCapitalShip_H
@@ -0,0 +1,146 @@
// ======================================================================
//
// AiShipBehaviorAttackFighter.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttackFighter_H
#define INCLUDED_AiShipBehaviorAttackFighter_H
#include "serverGame/AiShipBehaviorAttack.h"
#include "sharedFoundation/Timer.h"
#include "sharedObject/Object.h"
class AiPilotManager;
class NetworkId;
class ShipObject;
// ======================================================================
class AiShipBehaviorAttackFighter : public AiShipBehaviorAttack
{
public:
class Maneuver;
#ifdef _DEBUG
virtual void addDebug(AiDebugString & aiDebugString);
void debug_forceManeuver(int maneuverType);
#endif // _DEBUG
static Vector const calculateEvadePositionWithinLeashDistance_w(AiShipBehaviorAttack const & aiShipBehaviorAttack);
protected:
void setManeuver(Maneuver * const);
float getTimeDelta() const;
void setTimeDelta(float const timeDelta);
float getWeaponPriority(bool const missilesReady, bool const projectileReady, int const weaponIndex);
void alterWeapons();
void alterManeuverFlags();
void alterTargetInformation();
void alterManeuver();
void alterBooster();
AiPilotManager const & getPilotManagerInfo() const;
void setManeuverFlag(int const activeFlags, bool const setFlag);
bool hasManeuverFlag(int const activeFlags) const;
public:
class AiAttackTargetInformation
{
public:
AiAttackTargetInformation();
bool m_playerControlled;
float m_distanceToTarget;
float m_speed;
float m_weaponRange;
float m_radius;
bool m_facingTarget;
bool m_behindTarget;
Vector m_position_w;
Vector m_orientation_w;
Vector m_directionFromShip_w;
Vector m_offset; // aim offset
Vector m_maneuverPosition_w;
Timer m_offsetUpdate;
Timer m_positionUpdate;
bool m_isBoosting;
bool m_targetInProjectileConeOfFire;
bool m_targetWasInProjectileConeOfFire;
bool m_targetInMissileLockOnConeOfFire;
bool m_collisionCourse;
bool m_requestPositionUpdate;
bool m_inTargetsProjectileConeOfFire;
};
public:
explicit AiShipBehaviorAttackFighter(AiShipController & aiShipController);
explicit AiShipBehaviorAttackFighter(AiShipBehaviorAttack const & sourceBehavior);
virtual ~AiShipBehaviorAttackFighter();
virtual void alter(float timeDelta);
Vector const & getNextShotPosition_w() const;
float const getProjectileSpeed() const;
bool shouldStartToLeash() const;
bool shouldStartToEvade() const;
void alterAttackBehavior();
bool isFacingTarget() const;
bool isBehindTarget() const;
bool isTargetInProjectileConeOfFire() const;
float getDistanceToTargetSquared() const;
float getTimeSinceLastShot() const;
bool isNextProjectileShotPerfect() const;
private:
void initializeTimers();
void calculateEvadeHealthPercent();
int selectWeaponToFire(bool const includeMissles);
void calculateNextProjectileShotPerfect();
void calculateNextShotPosition_w();
void calculateWeaponProjectileSpeed();
Maneuver * m_currentManeuver;
float m_timeDelta;
Timer m_projectileTimer;
Timer m_missileLockOnTimer;
Timer m_missileFireDelayTimer;
Timer m_hitDecayTimer;
int m_stateFlags;
AiAttackTargetInformation * const m_targetInfo;
Vector m_missRadians;
int m_lastManeuverState;
int m_maneuverFlags;
int m_lastManeuverFlags;
float m_lastEvadeHealthPercent;
float m_evadeHealthPercent;
float m_timeSinceLastShot;
float m_projectileSpeed;
bool m_nextProjectileShotPerfect;
Vector m_shotErrorPosition_l;
Vector m_nextShotPosition_w;
private: // Disabled
AiShipBehaviorAttackFighter();
AiShipBehaviorAttackFighter(AiShipBehaviorAttackFighter const &);
AiShipBehaviorAttackFighter &operator =(AiShipBehaviorAttackFighter const &);
friend class Maneuver;
};
// ======================================================================
#endif //INCLUDED_AiShipBehaviorAttackFighter_H
@@ -0,0 +1,746 @@
// ======================================================================
//
// AiShipBehaviorAttackFighter_Maneuver.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorAttackFighter_Maneuver.h"
#include "serverGame/AiShipBehaviorAttackFighter_Maneuver_Path.h"
#include "serverGame/AiPilotManager.h"
#include "serverGame/AiShipController.h"
#include "serverGame/AiShipPilotData.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipObject.h"
#include "serverGame/SpaceAttackSquad.h"
#include "serverGame/SpaceSquad.h"
#include "sharedGame/ShipDynamicsModel.h"
#include "sharedLog/Log.h"
#include "sharedMath/Range.h"
#include "sharedTerrain/TerrainObject.h"
#include <vector>
// ======================================================================
namespace AiShipBehaviorAttackFighter_ManeuverNamespace
{
#ifdef _DEBUG
int s_sequenceId = 0;
#endif // _DEBUG
}
using namespace AiShipBehaviorAttackFighter_ManeuverNamespace;
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Maneuver(FighterManeuver const fm, AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo, float const maxTime, bool updateThrottle) :
m_aiShipBehaviorAttack(aiShipBehaviorAttack),
m_targetInfo(targetInfo),
m_pathList(new PathList),
m_currentPath(m_pathList->begin()),
m_currentPathNode(0),
m_abortFlags(0),
m_updateThrottle(updateThrottle),
m_throttleValue(0.0f),
m_desiredPosition_w(),
m_maneuverCategory(fm),
#ifdef _DEBUG
m_sequenceId(s_sequenceId++),
#endif // _DEBUG
m_expirationTimer(maxTime)
{
#ifdef _DEBUG
float const weaponAttackRange = getAiShipController().getAttackSquad().getWeaponAttackRange();
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled() && (weaponAttackRange <= 0.0f), "debug_ai", ("AiShipBehaviorAttackFighter::Maneuver::Maneuver() owner(%s) Why are we attacking if we have no weapons? weaponAttackRange(%.0f)", getAiShipController().getOwner()->getNetworkId().getValueString().c_str(), weaponAttackRange));
#endif // _DEBUG
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::~Maneuver()
{
for(PathList::iterator itPath = m_pathList->begin(); itPath != m_pathList->end(); ++itPath)
{
Path::deletePath(*itPath);
}
delete m_pathList;
m_currentPath = NULL;
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::FighterManeuver AiShipBehaviorAttackFighter::Maneuver::getFighterManeuver() const
{
return m_maneuverCategory;
}
// ----------------------------------------------------------------------
Vector const & AiShipBehaviorAttackFighter::Maneuver::getDesiredPosition_w() const
{
return m_desiredPosition_w;
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::setDesiredPosition_w(Vector const & position)
{
m_desiredPosition_w = position;
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::AiAttackTargetInformation const & AiShipBehaviorAttackFighter::Maneuver::getTargetInfo() const
{
return m_targetInfo;
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::isDesiredPositionBehindMe() const
{
Vector const position_o(getAiShipController().getOwner()->rotateTranslate_w2o(m_desiredPosition_w));
return (position_o.z < 0.0f);
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::addPath(Path * const path)
{
if (path)
{
m_pathList->push_back(path);
}
m_currentPath = m_pathList->begin();
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Path * AiShipBehaviorAttackFighter::Maneuver::getCurrentPath()
{
Path * currentPath = NULL;
if (!m_pathList->empty() && m_currentPath != m_pathList->end())
{
currentPath = *m_currentPath;
}
return currentPath;
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::alter(float timeDelta, int stateFlags)
{
bool shouldContinue = !m_expirationTimer.updateZero(timeDelta);
if (shouldContinue)
{
shouldContinue = alterPath(timeDelta);
}
if (shouldContinue)
{
shouldContinue = !(stateFlags & m_abortFlags);
}
// Modify the controller.
if (shouldContinue)
{
alterThrottle(timeDelta);
modifyController(timeDelta);
}
// let the caller know if it should continue.
return shouldContinue;
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::alterInternal(float const /*timeDelta*/)
{
return (getDesiredPosition_w() - getAiShipController().getOwnerPosition_w()).approximateMagnitude() > getAiShipController().getLargestTurnRadius();
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::alterPath(float const timeDelta)
{
bool shouldContinue = alterInternal(timeDelta);
//if (!shouldContinue)
//{
// Path * const currentPath = getCurrentPath();
// shouldContinue = currentPath ? selectNextPath() : false;
//}
return shouldContinue;
}
// ----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::selectNextPath()
{
bool shouldContinue = false;
if (!m_pathList->empty() && (m_currentPath != m_pathList->end()))
{
shouldContinue = ++m_currentPath != m_pathList->end();
m_currentPathNode = 0;
}
return shouldContinue;
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Path * AiShipBehaviorAttackFighter::Maneuver::addEmptyPath()
{
Path * newPath = Path::createPath();
addPath(newPath);
return newPath;
}
// ----------------------------------------------------------------------
// RLS -- Ensure the ship controller is modified in this block.
void AiShipBehaviorAttackFighter::Maneuver::modifyController(float const timeDelta)
{
getAiShipController().moveTo(m_desiredPosition_w, m_throttleValue, timeDelta);
}
// ----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::alterThrottle(float const /*timeDelta*/)
{
m_throttleValue = 1.0f;
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver * AiShipBehaviorAttackFighter::Maneuver::createManeuver(FighterManeuver const manueverType, AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo)
{
Maneuver * aiManeuver = NULL;
switch(manueverType)
{
case FM_chase:
aiManeuver = createManeuverChase(aiShipBehaviorAttack, targetInfo);
break;
case FM_leash:
aiManeuver = createManeuverLeash(aiShipBehaviorAttack, targetInfo);
break;
default:
case FM_none:
case FM_evade:
aiManeuver = createManeuverEvade(aiShipBehaviorAttack, targetInfo);
break;
}
return aiManeuver;
}
// ----------------------------------------------------------------------
AiShipController & AiShipBehaviorAttackFighter::Maneuver::getAiShipController()
{
return m_aiShipBehaviorAttack.getAiShipController();
}
// ----------------------------------------------------------------------
AiShipController const & AiShipBehaviorAttackFighter::Maneuver::getAiShipController() const
{
return m_aiShipBehaviorAttack.getAiShipController();
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
int AiShipBehaviorAttackFighter::Maneuver::getSequenceId() const
{
return m_sequenceId;
}
#endif // _DEBUG
// ----------------------------------------------------------------------
int AiShipBehaviorAttackFighter::Maneuver::getCurrentPathIndex() const
{
return m_currentPathNode;
}
//=======================================================================
class AiManeuver_Chase : public AiShipBehaviorAttackFighter::Maneuver
{
public:
AiManeuver_Chase(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiShipBehaviorAttackFighter::AiAttackTargetInformation const & targetInfo)
: Maneuver(FM_chase, aiShipBehaviorAttack, targetInfo, aiShipBehaviorAttack.getAiShipController().getPilotData()->m_fighterChaseMaxTime, true)
, m_chaseOnTailTimer(getAiShipController().getPilotData()->m_fighterChaseMaxOnTailTime)
, m_pursuitType(PT_lag)
, m_frontComfortDistance(0.0f)
, m_rearComfortDistance(0.0f)
{
// Calculate the front and rear comfort distances, when these distances are penetrated, the AI wants to stop chasing
ShipObject const * const primaryTargetShipObject = getAiShipController().getPrimaryAttackTargetShipObject();
if (primaryTargetShipObject != NULL)
{
float const ownerShipRadius = getAiShipController().getShipOwner()->getRadius();
float const ownerTurnRadius = getAiShipController().getLargestTurnRadius();
float const targetShipRadius = primaryTargetShipObject->getRadius();
m_frontComfortDistance = (targetShipRadius + (ownerShipRadius * 2.0f) + (ownerTurnRadius * 0.7f));
m_rearComfortDistance = (targetShipRadius + (ownerShipRadius * 2.0f) + (ownerTurnRadius * 0.3f));
}
else
{
// ERROR
}
calculateChaseDistance();
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Chase() owner(%s) isAttackSquadLeader(%s) NEW CHASE MANEUVER", getAiShipController().getOwner()->getNetworkId().getValueString().c_str(), getAiShipController().isAttackSquadLeader() ? "yes" : "no"));
if (getAiShipController().isAttackSquadLeader())
{
getAiShipController().getAttackSquad().setTooCloseToTarget(false);
}
setDesiredPosition_w(m_targetInfo.m_position_w);
}
virtual char const * const getFighterManeuverString() const;
protected:
bool alterInternal(float const /*timeDelta*/)
{
bool shouldContinue = true;
bool const attackSquadLeader = getAiShipController().isAttackSquadLeader();
calculateChaseDistance();
ShipObject const * const primaryTargetShipObject = getAiShipController().getPrimaryAttackTargetShipObject();
if (primaryTargetShipObject != NULL)
{
bool const facingTarget = m_aiShipBehaviorAttack.isFacingTarget();
if (facingTarget)
{
// Lead pursuit
setDesiredPosition_w(m_aiShipBehaviorAttack.getNextShotPosition_w());
m_pursuitType = PT_lead;
}
else
{
// Lag pursuit
float const chaseDistance = getAiShipController().getAttackSquad().getChaseDistance();
Vector const lagPursuitPosition_l(Vector(0.0f, 0.0f, -chaseDistance));
Vector const lagPursuitPosition_w(primaryTargetShipObject->getTransform_o2w().rotateTranslate_l2p(lagPursuitPosition_l));
setDesiredPosition_w(lagPursuitPosition_w);
m_pursuitType = PT_lag;
}
// If anyone in the attack squad is too close to the target, flag it
bool const behindTarget = m_aiShipBehaviorAttack.isBehindTarget();
float const tooCloseDistance = behindTarget ? m_rearComfortDistance : m_frontComfortDistance;
if (getDistanceToTargetSquared() <= sqr(tooCloseDistance))
{
getAiShipController().getAttackSquad().setTooCloseToTarget(true);
}
if (attackSquadLeader)
{
if (m_aiShipBehaviorAttack.shouldStartToLeash())
{
shouldContinue = false;
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Chase() owner(%s) CHASE BAILING - NEED TO LEASH", getAiShipController().getOwner()->getNetworkId().getValueString().c_str()));
}
else if (m_aiShipBehaviorAttack.shouldStartToEvade())
{
shouldContinue = false;
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Chase() owner(%s) CHASE BAILING - NEED TO EVADE", getAiShipController().getOwner()->getNetworkId().getValueString().c_str()));
}
}
}
else
{
// ERROR
}
//if (shouldContinue)
//{
// // See if we have been on the target's ass too long
//
// float const chaseDistance = getAiShipController().getAttackSquad().getChaseDistance();
//
// if (getDistanceToTargetSquared() < sqr(chaseDistance))
// {
// if (m_chaseOnTailTimer.updateZero(timeDelta))
// {
// shouldContinue = false;
// }
// }
// else
// {
// m_chaseOnTailTimer.reset();
// }
//}
return shouldContinue;
}
virtual void alterThrottle(float const /*timeDelta*/)
{
float const chaseDistance = getAiShipController().getAttackSquad().getChaseDistance();
float const distanceToTargetSquared = getDistanceToTargetSquared();
if ( (distanceToTargetSquared < sqr(chaseDistance))
&& m_targetInfo.m_playerControlled)
{
AiShipPilotData const & pilotData = *NON_NULL(getAiShipController().getPilotData());
m_throttleValue = pilotData.m_fighterChaseMinThrottle;
}
else
{
if (isDesiredPositionBehindMe())
{
m_throttleValue = 0.5f;
}
else
{
m_throttleValue = 1.0f;
}
}
}
private:
float getDistanceToTargetSquared()
{
return m_targetInfo.m_position_w.magnitudeBetweenSquared(getAiShipController().getOwnerPosition_w());
}
void calculateChaseDistance()
{
if (getAiShipController().isAttackSquadLeader())
{
ShipObject const * const primaryTargetShipObject = getAiShipController().getPrimaryAttackTargetShipObject();
if (primaryTargetShipObject != NULL)
{
AiShipPilotData const & pilotData = *NON_NULL(getAiShipController().getPilotData());
float const currentSpeed = getAiShipController().getShipOwner()->getCurrentSpeed();
float const seperationDistance = (currentSpeed * pilotData.m_fighterChaseSeperationTime);
float const chaseDistance = (m_rearComfortDistance * 1.2f) + seperationDistance;
getAiShipController().getAttackSquad().setChaseDistance(chaseDistance);
}
else
{
// ERROR
}
}
}
enum PursuitType
{
PT_lead,
PT_lag
};
Timer m_chaseOnTailTimer;
PursuitType m_pursuitType;
float m_frontComfortDistance;
float m_rearComfortDistance;
AiManeuver_Chase(AiManeuver_Chase const &);
AiManeuver_Chase();
AiManeuver_Chase const & operator=(AiManeuver_Chase const & rhs);
};
// ----------------------------------------------------------------------
char const * const AiManeuver_Chase::getFighterManeuverString() const
{
switch (m_pursuitType)
{
case PT_lead: { return "CHASE: LEAD PURSUIT"; }
case PT_lag: { return "CHASE: LAG PURSUIT"; }
default: {}
}
return "CHASE: INVALID";
}
//=======================================================================
class AiManeuver_Leash : public AiShipBehaviorAttackFighter::Maneuver
{
public:
AiManeuver_Leash(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiShipBehaviorAttackFighter::AiAttackTargetInformation const & targetInfo) :
Maneuver(FM_leash, aiShipBehaviorAttack, targetInfo, 100.0f, true)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Leash() owner(%s) isAttackSquadLeader(%s) NEW LEASH MANEUVER", getAiShipController().getOwner()->getNetworkId().getValueString().c_str(), getAiShipController().isAttackSquadLeader() ? "yes" : "no"));
setDesiredPosition_w(linearInterpolate(getAiShipController().getOwnerPosition_w(), getAiShipController().getSquad().getLeashAnchorPosition_w(), 1.0f - getAiShipController().getPilotAggression() * 0.5f));
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled() && (getDesiredPosition_w() == Vector::zero), "debug_ai", ("AiManeuver_Leash() ERROR: Desired Leash position set to Vector::zero."));
}
virtual char const * const getFighterManeuverString() const;
protected:
virtual bool alterInternal(float const timeDelta)
{
bool shouldContinue = Maneuver::alterInternal(timeDelta);
// See if we have leashed far enough back in
float const percentWithinLeashDistance = m_aiShipBehaviorAttack.getPercentWithinLeashDistance();
if (percentWithinLeashDistance > 0.25f)
{
shouldContinue = false;
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Leash() owner(%s) LEASH BAILING - WE HAVE LEASHED FAR ENOUGH", getAiShipController().getOwner()->getNetworkId().getValueString().c_str()));
}
return shouldContinue;
}
private:
AiManeuver_Leash(AiManeuver_Leash const &);
AiManeuver_Leash();
AiManeuver_Leash const & operator=(AiManeuver_Leash const & rhs);
};
// ----------------------------------------------------------------------
char const * const AiManeuver_Leash::getFighterManeuverString() const
{
return "LEASH";
}
//=======================================================================
class AiManeuver_Evade : public AiShipBehaviorAttackFighter::Maneuver
{
public:
AiManeuver_Evade(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiShipBehaviorAttackFighter::AiAttackTargetInformation const & targetInfo)
: Maneuver(FM_evade, aiShipBehaviorAttack, targetInfo, aiShipBehaviorAttack.getAiShipController().getPilotData()->m_fighterEvadeMaxTime, true)
, m_evadePositionUpdateTimer_w(getAiShipController().getPilotData()->m_fighterEvadePositionUpdateDelay)
, m_evadePositionUpdateTimer_l(4.0f)
, m_evadePosition_l()
, m_forceGetBehindTarget((rand() % 2) == 0)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiManeuver_Evade() owner(%s) isAttackSquadLeader(%s) NEW EVADE MANEUVER", getAiShipController().getOwner()->getNetworkId().getValueString().c_str(), getAiShipController().isAttackSquadLeader() ? "yes" : "no"));
calculateEvadePosition_l();
calculateDesiredPosition(0.0f);
}
virtual char const * const getFighterManeuverString() const;
protected:
bool alterInternal(float const timeDelta)
{
bool shouldContinue = true;
if (m_aiShipBehaviorAttack.isBehindTarget())
{
// If I am behind the target and and the target is moving fast enough, I need to turn around
// immediatelly to chase the target
float const ownerShipActualSpeedMaximum = getAiShipController().getShipOwner()->getShipActualSpeedMaximum();
if (m_targetInfo.m_speed > (ownerShipActualSpeedMaximum * 0.9f))
{
// Stop evading so we can do a lag pursuit
shouldContinue = false;
}
}
if (shouldContinue)
{
float const turnRadius = getAiShipController().getLargestTurnRadius();
float const weaponRange = getAiShipController().getAttackSquad().getProjectileAttackRange();
if (m_aiShipBehaviorAttack.getDistanceToTargetSquared() > sqr(weaponRange + turnRadius))
{
// We are far enough from the target to make an attack run, stop evading
shouldContinue = false;
}
else
{
if (m_forceGetBehindTarget)
{
if (m_targetInfo.m_inTargetsProjectileConeOfFire)
{
if (m_evadePositionUpdateTimer_l.updateZero(timeDelta))
{
// We have been targeted too much, change direction
m_evadePositionUpdateTimer_l.reset();
calculateEvadePosition_l();
}
}
if (m_evadePositionUpdateTimer_w.updateZero(timeDelta))
{
// Calculate a new evade position
m_evadePositionUpdateTimer_w.reset();
calculateDesiredPosition(timeDelta);
}
}
else if (m_targetInfo.m_inTargetsProjectileConeOfFire)
{
if (m_evadePositionUpdateTimer_l.updateZero(timeDelta))
{
// We have been targeted too much, change direction
m_evadePositionUpdateTimer_l.reset();
calculateEvadePosition_l();
}
if (m_evadePositionUpdateTimer_w.updateZero(timeDelta))
{
// Calculate a new evade position
m_evadePositionUpdateTimer_w.reset();
calculateDesiredPosition(timeDelta);
}
}
}
}
return shouldContinue;
}
virtual void alterThrottle(float const /*timeDelta*/)
{
if (isDesiredPositionBehindMe())
{
m_throttleValue = 0.5f;
}
else
{
m_throttleValue = 1.0f;
}
}
private:
void calculateDesiredPosition(float const deltaSeconds)
{
ShipObject const * const primaryTargetShipObject = getAiShipController().getPrimaryAttackTargetShipObject();
if (primaryTargetShipObject!= NULL)
{
ShipController const * const targetShipController = primaryTargetShipObject->getController()->asShipController();
if (targetShipController != NULL)
{
Transform transform;
Vector velocity;
targetShipController->getApproximateFutureTransform(transform, velocity, deltaSeconds);
setDesiredPosition_w(transform.rotateTranslate_l2p(m_evadePosition_l));
}
else
{
setDesiredPosition_w(primaryTargetShipObject->getTransform_o2w().rotateTranslate_l2p(m_evadePosition_l));
}
}
}
void calculateEvadePosition_l()
{
// Calculate the evade position relative to the -z axis of the target
AiShipPilotData const & pilotData = *NON_NULL(getAiShipController().getPilotData());
Transform transform;
float const rollAngle = Random::randomReal() * PI_TIMES_2;
transform.roll_l(rollAngle);
float const halfEvadeAngle = Random::randomReal() * pilotData.m_fighterEvadeAngle * 0.5f;
transform.pitch_l(halfEvadeAngle);
float const x = 0.0f;
float const y = 0.0f;
float const z = -10000.0f;
m_evadePosition_l = transform.rotateTranslate_l2p(Vector(x, y, z));
}
Timer m_evadePositionUpdateTimer_w;
Timer m_evadePositionUpdateTimer_l;
Vector m_evadePosition_l;
bool m_forceGetBehindTarget;
AiManeuver_Evade(AiManeuver_Evade const &);
AiManeuver_Evade();
AiManeuver_Evade const & operator=(AiManeuver_Evade const & rhs);
};
// ----------------------------------------------------------------------
char const * const AiManeuver_Evade::getFighterManeuverString() const
{
return "EVADE";
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver * AiShipBehaviorAttackFighter::Maneuver::createManeuverChase(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo)
{
return new AiManeuver_Chase(aiShipBehaviorAttack, targetInfo);
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver * AiShipBehaviorAttackFighter::Maneuver::createManeuverEvade(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo)
{
return new AiManeuver_Evade(aiShipBehaviorAttack, targetInfo);
}
// ----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver * AiShipBehaviorAttackFighter::Maneuver::createManeuverLeash(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo)
{
return new AiManeuver_Leash(aiShipBehaviorAttack, targetInfo);
}
// ======================================================================
@@ -0,0 +1,112 @@
// ======================================================================
//
// AiShipBehaviorAttackFighter_Maneuver.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttackFighter_Maneuver_H
#define INCLUDED_AiShipBehaviorAttackFighter_Maneuver_H
// ======================================================================
#include "serverGame/AiShipBehaviorAttackFighter.h"
class AiShipController;
//-----------------------------------------------------------------------
class AiShipBehaviorAttackFighter::Maneuver
{
public:
enum FighterManeuver
{
FM_none,
FM_chase,
FM_evade,
FM_leash
};
enum ManeuverFlags
{
MF_targetInAttackRange = 0x00000001,
MF_targetIsTooClose = 0x00000002,
MF_missileLockedOnMe = 0x00000004
};
Maneuver(FighterManeuver fm, AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo, float const maxTime, bool updateThrottle = true);
virtual ~Maneuver();
Vector const & getDesiredPosition_w() const;
void setDesiredPosition_w(Vector const & position);
AiAttackTargetInformation const & getTargetInfo() const;
bool isDesiredPositionBehindMe() const;
// Path management.
class Path;
typedef stdvector<Path*>::fwd PathList;
void addPath(Path * path);
Path * getCurrentPath();
bool selectNextPath();
Path * addEmptyPath();
int getCurrentPathIndex() const;
// Return positive if it should continue.
virtual bool alter(float timeDelta, int stateFlags);
virtual char const * const getFighterManeuverString() const = 0;
virtual FighterManeuver getFighterManeuver() const;
#ifdef _DEBUG
int getSequenceId() const;
#endif // _DEBUG
public:
static Maneuver * createManeuver(FighterManeuver const manueverType, AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo);
static Maneuver * createManeuverChase(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo);
static Maneuver * createManeuverEvade(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo);
static Maneuver * createManeuverLeash(AiShipBehaviorAttackFighter & aiShipBehaviorAttack, AiAttackTargetInformation const & targetInfo);
protected:
virtual bool alterPath(float const timeDelta);
virtual void alterThrottle(float const timeDelta);
virtual bool alterInternal(float const timeDelta);
virtual void modifyController(float const timeDelta);
AiShipController & getAiShipController();
AiShipController const & getAiShipController() const;
AiShipBehaviorAttackFighter & m_aiShipBehaviorAttack;
AiAttackTargetInformation const & m_targetInfo;
PathList * const m_pathList;
PathList::iterator m_currentPath;
int m_currentPathNode;
int m_abortFlags;
bool m_updateThrottle;
float m_throttleValue;
Vector m_desiredPosition_w;
FighterManeuver m_maneuverCategory;
#ifdef _DEBUG
int m_sequenceId;
#endif // _DEBUG
private:
Timer m_expirationTimer;
// Disabled
Maneuver();
Maneuver(Maneuver const &);
Maneuver const & operator=(Maneuver const & rhs);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorAttackFighter_Maneuver_H
@@ -0,0 +1,259 @@
// ======================================================================
//
// AiShipBehaviorAttackFighter_Maneuver_Path.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorAttackFighter_Maneuver_Path.h"
#include "sharedMath/Range.h"
#include "sharedMath/Vector.h"
#include "sharedMath/Transform.h"
#include "sharedRandom/Random.h"
#include "sharedFoundation/Misc.h"
#include <deque>
// ======================================================================
namespace AiShipBehaviorAttackFighter_Maneuver_Path
{
// You must pass in an initialized transform.
void constructLookAtTransformation(Transform & objectTransform, Vector const & lookAtPosition)
{
Vector const upVector(objectTransform.getLocalFrameJ_p());
Vector const objectPosition(objectTransform.getPosition_p());
Vector k = lookAtPosition - objectPosition;
if (!k.normalize())
return;
Vector i = upVector.cross(k);
if (!i.normalize())
return;
k = i.cross(upVector);
if (!k.normalize())
return;
objectTransform.setLocalFrameIJK_p(i, upVector, k);
}
}
using namespace AiShipBehaviorAttackFighter_Maneuver_Path;
// ======================================================================
AiShipBehaviorAttackFighter::Maneuver::Path::Path() :
m_nodeList(new NodeList)
{
}
//-----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Path::~Path()
{
delete m_nodeList;
}
//-----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::Path::getNextNode(Index & currentIndex, Node & desiredPosition, Transform const & currentLocation, float const distanceTolerance) const
{
bool hasNextNode = getNode(currentIndex, desiredPosition);
if (hasNextNode)
{
if ((desiredPosition - currentLocation.getPosition_p()).magnitudeSquared() < sqr(distanceTolerance))
{
currentIndex++;
}
}
return hasNextNode;
}
//-----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::Path::addNode(Node const & node)
{
m_nodeList->push_back(node);
}
//-----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::Path::getNode(Index const & index, Node & node) const
{
bool found = false;
if (!m_nodeList->empty() && index < static_cast<int>(m_nodeList->size()))
{
node = (*m_nodeList)[static_cast<const size_t>(index)];
found = true;
}
return found;
}
//-----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Path * AiShipBehaviorAttackFighter::Maneuver::Path::createPath()
{
return new Path;
}
//-----------------------------------------------------------------------
AiShipBehaviorAttackFighter::Maneuver::Path * AiShipBehaviorAttackFighter::Maneuver::Path::createPath(
PathTypes const pathType,
float const complexity,
float const tension,
float const objectRadius,
float const turnRadius,
Transform const & startTransform,
Vector const & endPosition)
{
float const pathLength = startTransform.getPosition_p().magnitudeBetween(endPosition);
// Ensure the path length is > 1.
DEBUG_WARNING(pathLength < 1.0f, ("Path length must be >= 1.0"));
Transform transformToEnd(startTransform);
constructLookAtTransformation(transformToEnd, endPosition);
DEBUG_WARNING(objectRadius < 1.0f, ("objectRadius must be >= 1.0"));
// Create a path length.
float const totalPathLengthDesired = std::max(pathLength, 1.0f) + turnRadius + objectRadius;
// Ensure totalPathLength is > 1.
DEBUG_WARNING(totalPathLengthDesired < 1.0f, ("Total path length desired must be >= 1.0"));
float const totalPathLength = std::max(totalPathLengthDesired, 1.0f);
float const turnRadiusPlusObjectRadius = (turnRadius + objectRadius) * 0.5f;
DEBUG_WARNING(turnRadiusPlusObjectRadius < 1.0f, ("turnRadiusPlusObjectRadius must be >= 1.0"));
// Generate the inner and outer radii
float const pathRadiusMultiplier = (1.0f + tension - complexity) * 0.5f;
float const radius1 = totalPathLength * Random::randomReal(0.0f, pathRadiusMultiplier);
float const radius2 = totalPathLength * Random::randomReal(0.0f, pathRadiusMultiplier);
float const minTurns = std::min(radius1, radius2) / std::max(objectRadius, 1.0f);
float const maxTurns = std::max(radius1, radius2) / std::max(objectRadius, 1.0f);
float const turns = Random::randomReal(minTurns, maxTurns);
// 0 = straight, 1 = parabolic1, 2 = parabolic2
int const mode = Random::random(0, static_cast<int>(complexity));
float const amp = Random::randomReal(0.0f, tension);
float const tms = Random::randomReal(0.0f, (tension + complexity) * 0.5f); // K
float const angle = Random::randomReal(PI_OVER_4, clamp(PI_OVER_4, PI_TIMES_2 * complexity, PI_TIMES_2));
Path * const path = NON_NULL(new Path);
Node node;
unsigned const int ncvs = static_cast<unsigned int>(totalPathLength / std::max(turnRadiusPlusObjectRadius, 1.0f)); // Number of CVs
float const ooHeight = 1.0f / totalPathLength;
float const sqrHeight = sqr(totalPathLength);
float const ooSqrHeight = 1.0f / sqrHeight;
for (unsigned i = 0; i < ncvs; i++)
{
node.z = static_cast<float>(i) * static_cast<float>(turnRadiusPlusObjectRadius);
float const tInterpolation = node.z * ooHeight;
float t0 = amp * sinf((tms * tInterpolation) + angle);
float t1 = 0.0f;
switch(mode)
{
case 0:
t1 = node.z * ooHeight;
break;
case 1:
t1 = sqr(node.z) * ooSqrHeight;
break;
default:
case 2:
t1 = sqrtf(node.z * ooHeight);
break;
}
float const t0t1Interpolant = t0 * (radius1 - (radius1 - radius2) * t1);
float const offset = (node.z * turns * 2.0f * PI) * ooHeight;
node.x = t0t1Interpolant * cosf(offset);
node.y = t0t1Interpolant * sinf(offset);
if (PT_loop == pathType)
{
Node const & loopNode = cubicInterpolate(transformToEnd.rotateTranslate_l2p(node), startTransform.getPosition_p(), tInterpolation);
path->addNode(loopNode);
}
else
{
path->addNode(transformToEnd.rotateTranslate_l2p(node));
}
}
return path;
}
//-----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::Path::deletePath(AiShipBehaviorAttackFighter::Maneuver::Path * path)
{
delete path;
}
//-----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::Path::clearNodes()
{
m_nodeList->clear();
}
//-----------------------------------------------------------------------
void AiShipBehaviorAttackFighter::Maneuver::Path::popFrontNode()
{
m_nodeList->pop_front();
}
//-----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::Path::isEmpty() const
{
return m_nodeList->empty();
}
//-----------------------------------------------------------------------
bool AiShipBehaviorAttackFighter::Maneuver::Path::getFrontNode(Node & node) const
{
bool success = !m_nodeList->empty();
if (success)
{
node = m_nodeList->front();
}
return success;
}
//-----------------------------------------------------------------------
int AiShipBehaviorAttackFighter::Maneuver::Path::getLength() const
{
return static_cast<int>(m_nodeList->size());
}
// ======================================================================
@@ -0,0 +1,67 @@
// ======================================================================
//
// AiShipBehaviorAttackFighter_Maneuver_Path.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorAttackFighter_Maneuver_Path_H
#define INCLUDED_AiShipBehaviorAttackFighter_Maneuver_Path_H
#include "serverGame/AiShipBehaviorAttackFighter_Maneuver.h"
class Transform;
// ======================================================================
class AiShipBehaviorAttackFighter::Maneuver::Path
{
public:
typedef Vector Node;
typedef int Index;
enum PathTypes
{
PT_empty,
PT_first,
PT_helix = PT_first,
PT_loop, // guarantees final point of the generated "createPath" path is the endPosition
PT_last = PT_loop,
PT_count = PT_last
};
bool getNextNode(Index & currentIndex, Node & desiredPosition, Transform const & currentLocation, float const distanceTolerance) const;
void addNode(Node const & node);
bool getNode(Index const & index, Node & node) const;
bool getFrontNode(Node & node) const;
bool isEmpty() const;
void popFrontNode();
void clearNodes();
int getLength() const;
static Path * createPath(PathTypes const pathType, // Selects the path type.
float const complexity, // Complexity of the path. (skill)
float const tension, // How tight the path follows control points. (aggresiveness)
float const objectRadius, // The size of the thing moving through the paths.
float const turnRadius,
Transform const & startXForm, // Starting position of the path.
Vector const & endPosition);
static Path * createPath();
static void deletePath(Path * path);
private:
Path();
virtual ~Path();
typedef stddeque<Node>::fwd NodeList;
NodeList * const m_nodeList;
private: // Disabled.
Path(Path const &);
Path &operator=(Path const &);
};
#endif
@@ -0,0 +1,93 @@
// ======================================================================
//
// AiShipBehaviorBase.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorBase.h"
#include "serverGame/AiShipController.h"
#include "serverGame/SpaceSquad.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedGame/AiDebugString.h"
#include "sharedObject/Object.h"
// ======================================================================
//
// AiShipBehaviorBase
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorBase::AiShipBehaviorBase(AiShipController & aiShipController)
: m_aiShipController(aiShipController)
{
}
// ----------------------------------------------------------------------
AiShipBehaviorBase::AiShipBehaviorBase(AiShipBehaviorBase const & rhs)
: m_aiShipController(rhs.m_aiShipController)
{
}
// ----------------------------------------------------------------------
AiShipBehaviorBase::~AiShipBehaviorBase()
{
}
// ----------------------------------------------------------------------
AiShipBehaviorType AiShipBehaviorBase::getBehaviorType() const
{
return ASBT_invalid;
}
// ----------------------------------------------------------------------
char const * AiShipBehaviorBase::getBehaviorString(AiShipBehaviorType const behavior)
{
switch (behavior)
{
case ASBT_idle: { return "IDLE"; }
case ASBT_track: { return "TRACK"; }
case ASBT_moveTo: { return "MOVETO"; }
case ASBT_patrol: { return "PATROL"; }
case ASBT_follow: { return "FOLLOW"; }
case ASBT_dock: { return "DOCK"; }
case ASBT_invalid:
default: break;
}
return "INVALID";
}
// ----------------------------------------------------------------------
AiShipController & AiShipBehaviorBase::getAiShipController()
{
return m_aiShipController;
}
// ----------------------------------------------------------------------
AiShipController const & AiShipBehaviorBase::getAiShipController() const
{
return m_aiShipController;
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
void AiShipBehaviorBase::addDebug(AiDebugString & aiDebugString)
{
aiDebugString.addText(FormattedString<512>().sprintf("%s\n", getBehaviorString(getBehaviorType())), PackedRgb::solidCyan);
}
#endif // _DEBUG
// ======================================================================
@@ -0,0 +1,67 @@
// ======================================================================
//
// AiShipBehaviorBase.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorBase_H
#define INCLUDED_AiShipBehaviorBase_H
class AiDebugString;
class AiShipController;
// ----------
// duped in ship_ai.scriptlib
enum AiShipBehaviorType
{
ASBT_idle = 0,
ASBT_track,
ASBT_moveTo,
ASBT_patrol,
ASBT_follow,
ASBT_dock,
ASBT_invalid
};
// ======================================================================
class AiShipBehaviorBase
{
public:
static char const * getBehaviorString(AiShipBehaviorType const behavior);
public:
explicit AiShipBehaviorBase(AiShipController & aiShipController);
AiShipBehaviorBase(AiShipBehaviorBase const & rhs);
virtual ~AiShipBehaviorBase() = 0;
virtual void alter(float deltaSeconds) = 0;
virtual AiShipBehaviorType getBehaviorType() const;
AiShipController & getAiShipController();
AiShipController const & getAiShipController() const;
#ifdef _DEBUG
virtual void addDebug(AiDebugString & aiDebugString);
#endif // _DEBUG
protected:
AiShipController & m_aiShipController;
private:
// Disabled
AiShipBehaviorBase();
AiShipBehaviorBase &operator =(AiShipBehaviorBase const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorBase_H
@@ -0,0 +1,688 @@
// ======================================================================
//
// AiShipBehaviorDock.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorDock.h"
#include "serverGame/AiShipController.h"
#include "serverGame/AiShipPilotData.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipObject.h"
#include "serverGame/SpaceDockingManager.h"
#include "serverGame/SpaceSquad.h"
#include "serverScript/GameScriptObject.h"
#include "serverScript/ScriptParameters.h"
#include "sharedCollision/BaseExtent.h"
#include "sharedCollision/CollisionProperty.h"
#include "sharedCollision/SpaceAvoidanceManager.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedGame/AiDebugString.h"
#include "sharedGame/CollisionCallbackManager.h"
#include "sharedLog/Log.h"
#include "sharedMath/AxialBox.h"
#include "sharedNetworkMessages/MessageQueueGenericValueType.h"
#include "sharedObject/Appearance.h"
#include "sharedObject/NetworkIdManager.h"
// ======================================================================
//
// AiShipBehaviorDockNamespace
//
// ======================================================================
namespace AiShipBehaviorDockNamespace
{
float s_tractorBeamErrorDistance = 1.0f;
}
using namespace AiShipBehaviorDockNamespace;
// ======================================================================
//
// AiShipBehaviorDock
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorDock::AiShipBehaviorDock(ShipController & shipController, ShipObject & dockTarget, float const secondsAtDock)
: m_shipController(shipController)
, m_dockTarget(dockTarget)
, m_timeAtDockTimer(secondsAtDock)
, m_approachHardPointList(new HardPointList)
, m_initialApproachHardPointCount(0)
, m_exitHardPointList(new HardPointList)
, m_dockHardPoint()
, m_landingHardPoint()
, m_hasLandingHardPoint(shipController.getOwner()->getAppearance()->findHardpoint(TemporaryCrcString("landing1", false), m_landingHardPoint))
, m_dockingState(DS_approach)
, m_dockingStateTime(0.0f)
, m_infiniteDockTime(secondsAtDock < 0.0f)
, m_dockFinished(false)
, m_goalPosition_w()
, m_wingsOpenedBeforeDock(m_shipController.getShipOwner()->hasWings() && m_shipController.getShipOwner()->wingsOpened())
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [1/6] unit(%s) dockTarget(%s) secondsAtDock(%.2f) landingHardPoint(%s)", (shipController.getOwner() != NULL) ? shipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner", dockTarget.getNetworkId().getValueString().c_str(), secondsAtDock, m_hasLandingHardPoint ? "yes" : "no"));
if (m_shipController.isBeingDocked())
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock() unit(%s) dockTarget(%s) ERROR: We can't dock with someone if we are currently being docked.", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
// Fail the docking
m_dockTarget = CachedNetworkId::cms_cachedInvalid;
}
if (m_shipController.getOwner()->getNetworkId() == dockTarget.getNetworkId())
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock() unit(%s) dockTarget(%s) ERROR: Why is the ship trying to dock with itself?", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
// Fail the docking
m_dockTarget = CachedNetworkId::cms_cachedInvalid;
}
if (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
{
SpaceDockingManager::fetchDockingProcedure(*m_shipController.getOwner(), dockTarget, m_dockHardPoint, *m_approachHardPointList, *m_exitHardPointList);
}
if ( (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
&& m_approachHardPointList->empty())
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock() unit(%s) dockTarget(%s) ERROR Why is the approach hard point list empty?", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
// Fail the docking
SpaceDockingManager::releaseDockingProcedure(m_shipController.getOwner()->getNetworkId(), m_dockTarget);
m_dockTarget = CachedNetworkId::cms_cachedInvalid;
}
if ( (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
&& m_exitHardPointList->empty())
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock() unit(%s) dockTarget(%s) ERROR Why is the exit hard point list empty?", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
// Fail the docking
SpaceDockingManager::releaseDockingProcedure(m_shipController.getOwner()->getNetworkId(), m_dockTarget);
m_dockTarget = CachedNetworkId::cms_cachedInvalid;
}
if (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
{
// Notify the ship that we want to dock with it
ShipController * const dockTargetShipController = dockTarget.getController()->asShipController();
if (dockTargetShipController != NULL)
{
dockTargetShipController->addDockedBy(*shipController.getOwner());
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock() ERROR: Why does this dockTarget(%s) not have a ship controller?", dockTarget.getDebugInformation().c_str()));
// Fail the docking
SpaceDockingManager::releaseDockingProcedure(m_shipController.getOwner()->getNetworkId(), m_dockTarget);
m_dockTarget = CachedNetworkId::cms_cachedInvalid;
}
}
if (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
{
// Turn off collision for the auth-client at this point
if (m_shipController.getShipOwner()->isPlayerShip())
{
m_shipController.appendMessage(CM_addIgnoreIntersect, 0.0f, new MessageQueueGenericValueType<NetworkId>(m_dockTarget), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT);
}
}
m_initialApproachHardPointCount = static_cast<int>(m_approachHardPointList->size());
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock() unit(%s) dockTarget(%s) approachHardPointCount(%u) exitHardPointCount(%u)", (shipController.getOwner() != NULL) ? shipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner", dockTarget.getNetworkId().getValueString().c_str(), m_approachHardPointList->size(), m_exitHardPointList->size()));
}
// ----------------------------------------------------------------------
AiShipBehaviorDock::~AiShipBehaviorDock()
{
ShipObject * const ownerShipObject = m_shipController.getShipOwner();
// Open the wings
if ( (ownerShipObject != NULL)
&& m_wingsOpenedBeforeDock)
{
m_shipController.getShipOwner()->openWings();
}
// Turn collision back on
if (m_dockTarget != CachedNetworkId::cms_cachedInvalid)
{
CollisionCallbackManager::removeIgnoreIntersect(m_shipController.getOwner()->getNetworkId(), m_dockTarget);
if ( (ownerShipObject != NULL)
&& ownerShipObject->isPlayerShip())
{
m_shipController.appendMessage(CM_removeIgnoreIntersect, 0.0f, new MessageQueueGenericValueType<NetworkId>(m_dockTarget), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT);
}
}
// Notify the dock target that we are done docking with it
Object * const dockTarget = m_dockTarget.getObject();
if (dockTarget != NULL)
{
ShipController * const dockTargetShipController = dockTarget->getController()->asShipController();
if (dockTargetShipController != NULL)
{
dockTargetShipController->removeDockedBy(*m_shipController.getOwner());
}
}
delete m_approachHardPointList;
delete m_exitHardPointList;
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::alter(float deltaSeconds)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorDock::alter");
bool abortDocking = false;
if (m_dockTarget.getObject() == NULL)
{
// If we lose the dock target, fail the docking procedure.
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::alter() unit(%s) dockTarget(%s) DOCK TARGET LOST...UNDOCKING", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
abortDocking = true;
}
else
{
// If the dock target is an AI ship and it begins attacking, stop the docking procedure.
AiShipController * const dockTargetAiShipController = AiShipController::asAiShipController(m_dockTarget.getObject()->getController());
if ( (dockTargetAiShipController != NULL)
&& dockTargetAiShipController->isAttacking())
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::alter() unit(%s) dockTarget(%s) DOCK TARGET IS ATTACKING...UNDOCKING", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
abortDocking = true;
}
}
if (abortDocking)
{
if (m_timeAtDockTimer.isExpired())
{
triggerUnDockWithSuccess();
}
else
{
triggerUnDockWithFailure();
}
}
else
{
// Continue docking
m_dockingStateTime += deltaSeconds;
switch (m_dockingState)
{
case DS_approach: { approach(deltaSeconds); } break;
case DS_approachTractorBeam: { approachTractorBeam(deltaSeconds); } break;
case DS_landing: { landing(deltaSeconds); } break;
case DS_docked: { docked(deltaSeconds); } break;
case DS_exitTractorBeam: { unDock(deltaSeconds); } break;
default: { FATAL(true, ("Unexpected docking procedure")); } break;
}
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::approach(float const deltaSeconds)
{
setApproachPosition();
float const distanceToGoalSquared = m_shipController.getOwner()->getPosition_w().magnitudeBetweenSquared(m_goalPosition_w);
float const turnRadius = m_shipController.getLargestTurnRadius();
if (distanceToGoalSquared <= sqr(turnRadius))
{
// Start the approach tractor beam
m_dockingState = DS_approachTractorBeam;
// Turn off collision
CollisionCallbackManager::addIgnoreIntersect(m_shipController.getOwner()->getNetworkId(), m_dockTarget);
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [2/6] unit(%s) dockTarget(%s) TRACTOR BEAM", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
}
else
{
// Move the unit towards the first approach position
m_shipController.setThrottle(1.0f);
Vector resultAvoidancePosition_w;
Vector const & shipVelocity = m_shipController.getShipOwner()->getCurrentVelocity_p();
if (SpaceAvoidanceManager::getAvoidancePosition(*m_shipController.getOwner(), shipVelocity, m_goalPosition_w, resultAvoidancePosition_w))
{
IGNORE_RETURN(m_shipController.face(resultAvoidancePosition_w, deltaSeconds));
}
else
{
IGNORE_RETURN(m_shipController.face(m_goalPosition_w, deltaSeconds));
}
}
// Close the wings
if (m_wingsOpenedBeforeDock)
{
m_shipController.getShipOwner()->closeWings();
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::approachTractorBeam(float const deltaSeconds)
{
m_shipController.setThrottle(0.0f);
setApproachPosition();
Vector const & ownerPosition_w = m_shipController.getOwner()->getPosition_w();
float const distanceToGoalSquared = ownerPosition_w.magnitudeBetweenSquared(m_goalPosition_w);
if ( m_approachHardPointList->empty()
&& (distanceToGoalSquared < sqr(s_tractorBeamErrorDistance)))
{
if (alignWithDock(deltaSeconds))
{
// Start the landing tractor beam
m_dockingState = DS_landing;
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [3/6] unit(%s) dockTarget(%s) LANDING", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
}
}
else
{
if (distanceToGoalSquared < sqr(s_tractorBeamErrorDistance))
{
Vector const forward_w(m_dockTarget.getObject()->rotateTranslate_o2w(m_approachHardPointList->back().rotateTranslate_l2p(Vector(100000.0f, 0.0f, 0.0f))));
Vector const up_w(m_dockTarget.getObject()->rotateTranslate_o2w(m_approachHardPointList->back().rotateTranslate_l2p(Vector(0.0f, 0.0f, -100000.0f))));
if (m_shipController.face(forward_w, up_w, deltaSeconds))
{
// Move to the next approach point
if (!m_approachHardPointList->empty())
{
m_approachHardPointList->pop_back();
}
}
}
else
{
bool const allowOrientation = (m_initialApproachHardPointCount == static_cast<int>(m_approachHardPointList->size()));
tractorBeamToGoalPosition(deltaSeconds, allowOrientation);
if (allowOrientation)
{
IGNORE_RETURN(m_shipController.face(m_goalPosition_w, deltaSeconds));
}
}
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::landing(float const deltaSeconds)
{
m_shipController.setThrottle(0.0f);
setDockPosition();
Vector const & ownerPosition_w = m_shipController.getOwner()->getPosition_w();
float const distanceToGoalSquared = ownerPosition_w.magnitudeBetweenSquared(m_goalPosition_w);
if (distanceToGoalSquared < sqr(s_tractorBeamErrorDistance))
{
triggerDocked();
}
if (m_dockingState == DS_landing)
{
bool const allowOrientation = false;
tractorBeamToGoalPosition(deltaSeconds, allowOrientation);
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::docked(float const deltaSeconds)
{
m_shipController.setThrottle(0.0f);
// Run the dock timer
if ( !m_infiniteDockTime
&& m_timeAtDockTimer.updateNoReset(deltaSeconds))
{
triggerStartUnDock();
unDock();
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::unDock(float const deltaSeconds)
{
if (!m_exitHardPointList->empty())
{
setExitPosition();
}
// Lerp the ship to the goal position
Vector const & ownerPosition_w = m_shipController.getOwner()->getPosition_w();
float const distanceToGoalSquared = ownerPosition_w.magnitudeBetweenSquared(m_goalPosition_w);
if (distanceToGoalSquared < sqr(s_tractorBeamErrorDistance))
{
if (m_exitHardPointList->empty())
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [6/6] unit(%s) dockTarget(%s) UNDOCKED", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
if (m_timeAtDockTimer.isExpired())
{
triggerUnDockWithSuccess();
}
else
{
// The docking was stopped prematurely
triggerUnDockWithFailure();
}
m_dockFinished = true;
}
else
{
m_exitHardPointList->pop_front();
}
}
if (m_dockingState == DS_exitTractorBeam)
{
bool const allowOrientation = false;
tractorBeamToGoalPosition(deltaSeconds, allowOrientation);
}
}
// ----------------------------------------------------------------------
bool AiShipBehaviorDock::alignWithDock(float const deltaSeconds)
{
CollisionProperty const * const ownerCollisionProperty = NON_NULL(m_shipController.getOwner()->getCollisionProperty());
AxialBox const ownerAxialBox = ownerCollisionProperty->getExtent_l()->getBoundingBox();
Vector forward_l;
Vector up_l;
float const width = ownerAxialBox.getWidth();
float const height = ownerAxialBox.getHeight();
float const depth = ownerAxialBox.getDepth();
if ( (width < height)
&& (width < depth))
{
forward_l = Vector::unitX;
up_l = Vector::unitY;
}
else if (height <= depth)
{
forward_l = Vector::unitX;
up_l = -Vector::unitZ;
}
else
{
forward_l = Vector::unitZ;
up_l = Vector::unitY;
}
Vector const forward_w(m_dockTarget.getObject()->rotateTranslate_o2w(m_dockHardPoint.rotateTranslate_l2p(forward_l * 100000.0f)));
Vector const up_w(m_dockTarget.getObject()->rotateTranslate_o2w(m_dockHardPoint.rotateTranslate_l2p(up_l * 100000.0f)));
return m_shipController.face(forward_w, up_w, deltaSeconds);
}
// ----------------------------------------------------------------------
bool AiShipBehaviorDock::isDocked() const
{
return (m_dockingState == DS_docked);
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::triggerDocked()
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [4/6] unit(%s) dockTarget(%s) timeAtDock(%.2f) DOCKED", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str(), m_timeAtDockTimer.getExpireTime()));
m_dockingState = DS_docked;
m_dockingStateTime = 0.0f;
GameScriptObject * const gameScriptObject = GameScriptObject::asGameScriptObject(m_shipController.getOwner());
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
scriptParams.addParam(m_dockTarget);
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_DOCKED, scriptParams));
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::triggerDocked() unit(%s) dockTarget(%s)", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock::triggerDocked() ERROR: Unable to get the ScriptObject for this object(%s)", m_shipController.getOwner()->getDebugInformation().c_str()));
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::triggerStartUnDock()
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock: [5/6] unit(%s) dockTarget(%s) START UNDOCK", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
GameScriptObject * const gameScriptObject = GameScriptObject::asGameScriptObject(m_shipController.getOwner());
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
scriptParams.addParam(m_dockTarget);
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_START_UNDOCK, scriptParams));
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::triggerStartUnDock() unit(%s) dockTarget(%s)", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock::triggerStartUnDock() ERROR: Unable to get the ScriptObject for this object(%s)", m_shipController.getOwner()->getDebugInformation().c_str()));
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::triggerUnDockWithSuccess()
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::triggerUnDockWithSuccess() unit(%s) dockTarget(%s)", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
GameScriptObject * const gameScriptObject = GameScriptObject::asGameScriptObject(m_shipController.getOwner());
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
scriptParams.addParam(m_dockTarget);
scriptParams.addParam(true);
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_UNDOCKED, scriptParams));
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock::triggerUnDockWithSuccess() ERROR: Unable to get the ScriptObject for this object(%s)", m_shipController.getOwner()->getDebugInformation().c_str()));
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::triggerUnDockWithFailure()
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::triggerUnDockWithFailure() unit(%s) dockTarget(%s)", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
m_dockFinished = true;
GameScriptObject * const gameScriptObject = GameScriptObject::asGameScriptObject(m_shipController.getOwner());
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
scriptParams.addParam(m_dockTarget);
scriptParams.addParam(false);
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_UNDOCKED, scriptParams));
}
else
{
DEBUG_WARNING(true, ("debug_ai: AiShipBehaviorDock::triggerUnDockWithFailure() ERROR: Unable to get the ScriptObject for this object(%s)", m_shipController.getOwner()->getDebugInformation().c_str()));
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::unDock()
{
// If the ship was still getting to the approach point, immediatelly fail the dock, if the ship was in the middle of the docking procedure, send the ship out the exit path and release it
if (m_dockingState == DS_approach)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::unDock() unit(%s) dockTarget(%s) ABORTING IMMEDIATELLY", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
triggerUnDockWithFailure();
}
else
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::unDock() unit(%s) dockTarget(%s) GOING TO EXIT PATH", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
m_dockingState = DS_exitTractorBeam;
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::setApproachPosition()
{
if (!m_approachHardPointList->empty())
{
Transform const & transform = m_approachHardPointList->back();
m_goalPosition_w = m_dockTarget.getObject()->rotateTranslate_o2w(transform.getPosition_p());
}
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::setDockPosition()
{
m_goalPosition_w = m_dockTarget.getObject()->rotateTranslate_o2w(m_dockHardPoint.getPosition_p());
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::setExitPosition()
{
if (!m_exitHardPointList->empty())
{
m_goalPosition_w = m_dockTarget.getObject()->rotateTranslate_o2w(m_exitHardPointList->front().getPosition_p());
}
else
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorDock::setExitPosition() unit(%s) dockTarget(%s) Why is the exit hard point list empty?", m_shipController.getOwner()->getDebugInformation().c_str(), m_dockTarget.getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
bool AiShipBehaviorDock::isDockFinished() const
{
return m_dockFinished;
}
// ----------------------------------------------------------------------
CachedNetworkId const & AiShipBehaviorDock::getDockTarget() const
{
return m_dockTarget;
}
// ----------------------------------------------------------------------
float AiShipBehaviorDock::getMaxTractorBeamSpeed() const
{
float const shipActualSpeedMaximum = m_shipController.getShipOwner()->getShipActualSpeedMaximum();
AiShipController * const aiShipController = m_shipController.asAiShipController();
return (aiShipController != NULL) ? (shipActualSpeedMaximum * aiShipController->getPilotData()->m_nonCombatMaxSpeedPercent) : shipActualSpeedMaximum;
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::tractorBeamToGoalPosition(float const deltaSeconds, bool const allowOrientation)
{
// Lerp the ship to the goal position, but only as fast as the ship can actually move
float const maxTractorBeamSpeed = getMaxTractorBeamSpeed() * deltaSeconds;
// See if we are close enough to the goal position
Vector const & ownerPosition_w = m_shipController.getOwner()->getPosition_w();
if (ownerPosition_w.magnitudeBetween(m_goalPosition_w) <= maxTractorBeamSpeed)
{
m_shipController.setPosition_w(m_goalPosition_w, allowOrientation);
}
else
{
// Still tractor beaming towards the goal position
Vector directionToGoalPosition(m_goalPosition_w - ownerPosition_w);
directionToGoalPosition.normalize();
Vector const newPosition(ownerPosition_w + (directionToGoalPosition * maxTractorBeamSpeed));
m_shipController.setPosition_w(newPosition, allowOrientation);
}
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
char const * AiShipBehaviorDock::getDockingStateString(DockingState const dockingState)
{
switch (dockingState)
{
case DS_approach: { return "APPROACH"; }
case DS_approachTractorBeam: { return "APPROACH TRACTOR BEAM"; }
case DS_landing: { return "LANDING"; }
case DS_docked: { return "DOCKED"; }
case DS_exitTractorBeam: { return "EXIT TRACTOR BEAM"; }
default: break;
};
return "";
}
// ----------------------------------------------------------------------
void AiShipBehaviorDock::addDebug(AiDebugString & aiDebugString)
{
aiDebugString.addText(FormattedString<512>().sprintf("DOCKING[%s]\n", getDockingStateString(m_dockingState)), PackedRgb::solidCyan);
aiDebugString.addLineToPosition(m_goalPosition_w, PackedRgb::solidCyan);
if (m_dockTarget.getObject() != NULL)
{
Transform transform;
transform.multiply(m_dockTarget.getObject()->getTransform_o2w(), m_dockHardPoint);
aiDebugString.addAxis(transform, 40.0f);
}
}
#endif // _DEBUG
// ======================================================================
@@ -0,0 +1,98 @@
// ======================================================================
//
// AiShipBehaviorDock.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorDock_H
#define INCLUDED_AiShipBehaviorDock_H
#include "sharedFoundation/Timer.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Vector.h"
#include "sharedObject/CachedNetworkId.h"
class AiDebugString;
class NetworkId;
class ShipController;
class ShipObject;
// ======================================================================
class AiShipBehaviorDock
{
public:
AiShipBehaviorDock(ShipController & shipController, ShipObject & dockTarget, float const secondsAtDock);
~AiShipBehaviorDock();
void alter(float deltaSeconds);
bool isDocked() const;
void unDock();
bool isDockFinished() const;
CachedNetworkId const & getDockTarget() const;
#ifdef _DEBUG
void addDebug(AiDebugString & aiDebugString);
#endif // _DEBUG
private:
enum DockingState
{
DS_approach,
DS_approachTractorBeam,
DS_landing,
DS_docked,
DS_exitTractorBeam
};
#ifdef _DEBUG
static char const * getDockingStateString(DockingState const dockingState);
#endif // _DEBUG
typedef stdlist<Transform>::fwd HardPointList;
ShipController & m_shipController;
CachedNetworkId m_dockTarget;
Timer m_timeAtDockTimer;
HardPointList * const m_approachHardPointList;
int m_initialApproachHardPointCount;
HardPointList * const m_exitHardPointList;
Transform m_dockHardPoint;
Transform m_landingHardPoint;
bool m_hasLandingHardPoint;
DockingState m_dockingState;
float m_dockingStateTime;
bool m_infiniteDockTime;
bool m_dockFinished;
Vector m_goalPosition_w;
bool m_wingsOpenedBeforeDock;
void approach(float const deltaSeconds);
void approachTractorBeam(float const deltaSeconds);
void landing(float const deltaSeconds);
void docked(float const deltaSeconds);
void unDock(float const deltaSeconds);
bool alignWithDock(float const deltaSeconds);
void setApproachPosition();
void setDockPosition();
void setExitPosition();
void triggerDocked();
void triggerStartUnDock();
void triggerUnDockWithSuccess();
void triggerUnDockWithFailure();
float getMaxTractorBeamSpeed() const;
void tractorBeamToGoalPosition(float const deltaSeconds, bool const allowOrientation);
// Disabled
AiShipBehaviorDock();
AiShipBehaviorDock(AiShipBehaviorDock const &);
AiShipBehaviorDock &operator =(AiShipBehaviorDock const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorDock_H
@@ -0,0 +1,133 @@
// ======================================================================
//
// AiShipBehaviorFollow.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorFollow.h"
#include "serverGame/AiShipController.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/Formation.h"
#include "serverGame/ShipObject.h"
#include "serverGame/SpaceSquad.h"
#include "serverScript/GameScriptObject.h"
#include "serverScript/ScriptParameters.h"
#include "sharedFoundation/NetworkId.h"
#include "sharedLog/Log.h"
// ======================================================================
//
// AiShipBehaviorFollowNamespace
//
// ======================================================================
// ----------------------------------------------------------------------
namespace AiShipBehaviorFollowNamespace
{
float slowDownRequestRadiusGain = 0.9f;
}
using namespace AiShipBehaviorFollowNamespace;
// ======================================================================
//
// AiShipBehaviorFollow
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorFollow::AiShipBehaviorFollow(AiShipController & aiShipController, NetworkId const & followedUnit)
: AiShipBehaviorBase(aiShipController)
, m_followedUnit(followedUnit)
, m_followedUnitLost(false)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorFollow::AiShipBehaviorFollow() unit(%s) followedUnit(%s)", (m_aiShipController.getOwner() != NULL) ? m_aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner", followedUnit.getValueString().c_str()));
DEBUG_WARNING((m_followedUnit.getObject() == NULL), ("Trying to follow a NULL object."));
}
// ----------------------------------------------------------------------
void AiShipBehaviorFollow::alter(float const deltaSeconds)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorFollow::alter");
// Get the goal position
Object * const followedUnitObject = m_followedUnit.getObject();
Vector goalPosition_w;
if (followedUnitObject != NULL)
{
goalPosition_w = Formation::getPosition_w(followedUnitObject->getTransform_o2w(), m_aiShipController.getFormationPosition_l());
// Determine if the unit being followed is far enough away to request it to slow down
if (m_aiShipController.getOwner()->getPosition_w().magnitudeBetweenSquared(goalPosition_w) > sqr(m_aiShipController.getLargestTurnRadius() * slowDownRequestRadiusGain))
{
ShipController * const shipController = followedUnitObject->getController()->asShipController();
AiShipController * const aiShipController = (shipController != NULL) ? shipController->asAiShipController() : NULL;
if (aiShipController != NULL)
{
aiShipController->requestSlowDown();
}
}
}
else
{
if (!m_followedUnitLost)
{
m_followedUnitLost = true;
triggerFollowedUnitLost();
}
// Handle the case where we could not resolve the goal position
Object const * const object = m_aiShipController.getOwner();
if (object != NULL)
{
goalPosition_w = object->getPosition_w();
}
}
// Calculate the throttle
float const throttle = m_aiShipController.calculateThrottleToPosition_w(goalPosition_w, m_aiShipController.getLargestTurnRadius());
// Move the ship
m_aiShipController.moveTo(goalPosition_w, throttle, deltaSeconds);
}
// ----------------------------------------------------------------------
void AiShipBehaviorFollow::triggerFollowedUnitLost()
{
Object * object = m_aiShipController.getOwner();
ServerObject *serverObject = (object != NULL) ? object->asServerObject() : NULL;
GameScriptObject * gameScriptObject = (serverObject != NULL) ? serverObject->getScriptObject() : NULL;
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
scriptParams.addParam(m_followedUnit);
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_FOLLOW_LOST, scriptParams));
}
else
{
WARNING(true, ("Unable to get the ScriptObject for this object."));
}
}
// ----------------------------------------------------------------------
AiShipBehaviorType AiShipBehaviorFollow::getBehaviorType() const
{
return ASBT_follow;
}
// ======================================================================
@@ -0,0 +1,44 @@
// ======================================================================
//
// AiShipBehaviorFollow.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorFollow_H
#define INCLUDED_AiShipBehaviorFollow_H
#include "serverGame/AiShipBehaviorBase.h"
#include "sharedObject/CachedNetworkId.h"
class AiShipController;
class NetworkId;
// ======================================================================
class AiShipBehaviorFollow : public AiShipBehaviorBase
{
public:
AiShipBehaviorFollow(AiShipController & aiShipController, NetworkId const & followedUnit);
virtual void alter(float deltaSeconds);
virtual AiShipBehaviorType getBehaviorType() const;
private:
void triggerFollowedUnitLost();
CachedNetworkId m_followedUnit;
bool m_followedUnitLost;
// Disabled
AiShipBehaviorFollow();
AiShipBehaviorFollow(AiShipBehaviorFollow const &);
AiShipBehaviorFollow &operator =(AiShipBehaviorFollow const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorFollow_H
@@ -0,0 +1,44 @@
// ======================================================================
//
// AiShipBehaviorIdle.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorIdle.h"
#include "serverGame/AiShipController.h"
#include "serverGame/ConfigServerGame.h"
#include "sharedDebug/Profiler.h"
#include "sharedLog/Log.h"
// ======================================================================
//
// AiShipBehaviorIdle
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorIdle::AiShipBehaviorIdle(AiShipController & aiShipController)
: AiShipBehaviorBase(aiShipController)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorIdle() unit(%s)", (m_aiShipController.getOwner() != NULL) ? m_aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner"));
}
// ----------------------------------------------------------------------
void AiShipBehaviorIdle::alter(float const /*deltaSeconds*/)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorIdle::alter");
}
// ----------------------------------------------------------------------
AiShipBehaviorType AiShipBehaviorIdle::getBehaviorType() const
{
return ASBT_idle;
}
// ======================================================================
@@ -0,0 +1,36 @@
// ======================================================================
//
// AiShipBehaviorIdle.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorIdle_H
#define INCLUDED_AiShipBehaviorIdle_H
#include "serverGame/AiShipBehaviorBase.h"
class AiShipController;
// ======================================================================
class AiShipBehaviorIdle : public AiShipBehaviorBase
{
public:
explicit AiShipBehaviorIdle(AiShipController & aiShipController);
virtual void alter(float deltaSeconds);
virtual AiShipBehaviorType getBehaviorType() const;
private:
// Disabled
AiShipBehaviorIdle();
AiShipBehaviorIdle(AiShipBehaviorIdle const &);
AiShipBehaviorIdle &operator =(AiShipBehaviorIdle const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorIdle_H
@@ -0,0 +1,51 @@
// ======================================================================
//
// AiShipBehaviorTrack.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorTrack.h"
#include "serverGame/AiShipController.h"
#include "serverGame/ConfigServerGame.h"
#include "sharedDebug/Profiler.h"
#include "sharedLog/Log.h"
#include "sharedObject/Object.h"
// ======================================================================
//
// AiShipBehaviorTrack
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorTrack::AiShipBehaviorTrack(AiShipController & aiShipController, Object const & target)
: AiShipBehaviorBase(aiShipController)
, m_target(&target)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorTrack() unit(%s) target(%s)", (m_aiShipController.getOwner() != NULL) ? m_aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner", target.getNetworkId().getValueString().c_str()));
}
// ----------------------------------------------------------------------
void AiShipBehaviorTrack::alter(float deltaSeconds)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorTrack::alter");
if (m_target != NULL)
{
IGNORE_RETURN(m_aiShipController.face(m_target->getPosition_w(), deltaSeconds));
}
}
// ----------------------------------------------------------------------
AiShipBehaviorType AiShipBehaviorTrack::getBehaviorType() const
{
return ASBT_track;
}
// ======================================================================
@@ -0,0 +1,41 @@
// ======================================================================
//
// AiShipBehaviorTrack.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorTrack_H
#define INCLUDED_AiShipBehaviorTrack_H
#include "serverGame/AiShipBehaviorBase.h"
#include "sharedFoundation/Watcher.h"
class AiShipController;
class Object;
// ======================================================================
class AiShipBehaviorTrack : public AiShipBehaviorBase
{
public:
AiShipBehaviorTrack(AiShipController & aiShipController, Object const & target);
virtual void alter(float deltaSeconds);
virtual AiShipBehaviorType getBehaviorType() const;
private:
ConstWatcher<Object> m_target;
// Disabled
AiShipBehaviorTrack();
AiShipBehaviorTrack(AiShipBehaviorTrack const &);
AiShipBehaviorTrack &operator =(AiShipBehaviorTrack const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorTrack_H
@@ -0,0 +1,270 @@
// ======================================================================
//
// AiShipBehaviorWaypoint.cpp
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipBehaviorWaypoint.h"
#include "serverGame/AiShipController.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipObject.h"
#include "serverGame/SpacePath.h"
#include "serverGame/SpacePathManager.h"
#include "serverScript/GameScriptObject.h"
#include "serverScript/ScriptParameters.h"
#include "sharedCollision/CollisionProperty.h"
#include "sharedFoundation/FormattedString.h"
#include "sharedGame/AiDebugString.h"
#include "sharedLog/Log.h"
#include "sharedTerrain/TerrainObject.h"
// ======================================================================
//
// AiShipBehaviorWaypoint
//
// ======================================================================
// ----------------------------------------------------------------------
AiShipBehaviorWaypoint::AiShipBehaviorWaypoint(AiShipController & aiShipController, bool const cyclic)
: AiShipBehaviorBase(aiShipController)
, m_cyclic(cyclic)
, m_moveToCompleteTriggerSent(false)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorWaypoint::AiShipBehaviorWaypoint() unit(%s) cyclic(%s)", (aiShipController.getOwner() != NULL) ? aiShipController.getOwner()->getNetworkId().getValueString().c_str() : "NULL owner", cyclic ? "yes" : "no"));
}
// ----------------------------------------------------------------------
void AiShipBehaviorWaypoint::alter(float deltaSeconds)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipBehaviorWaypoint::alter");
// Get the goal position
Vector goalPosition_w;
{
if (!getNextPosition_w(goalPosition_w))
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorWaypoint::alter() unit(%s) Why do we have a path with no points in it?", m_aiShipController.getOwner()->getNetworkId().getValueString().c_str()));
goalPosition_w = m_aiShipController.getOwnerPosition_w();
}
}
// Calculate the throttle
float throttle = 1.0f;
{
SpacePath const * const path = m_aiShipController.getPath();
if ( (path != NULL)
&& !m_cyclic
&& (m_aiShipController.getCurrentPathIndex() == (path->getTransformList().size() - 1)))
{
throttle = m_aiShipController.calculateThrottleToPosition_w(goalPosition_w, m_aiShipController.getLargestTurnRadius());
// See if we need to send the move to complete trigger
if ( !m_moveToCompleteTriggerSent
&& m_aiShipController.getOwnerPosition_w().magnitudeBetweenSquared(goalPosition_w) < sqr(m_aiShipController.getLargestTurnRadius()))
{
m_moveToCompleteTriggerSent = true;
GameScriptObject * const gameScriptObject = GameScriptObject::asGameScriptObject(m_aiShipController.getOwner());
if(gameScriptObject != NULL)
{
ScriptParams scriptParams;
IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_UNIT_MOVE_TO_COMPLETE, scriptParams));
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "debug_ai", ("AiShipBehaviorWaypoint::alter() unit(%s) Trigger sent: TRIG_SPACE_UNIT_MOVE_TO_COMPLETE", m_aiShipController.getOwner()->getDebugInformation().c_str()));
}
else
{
DEBUG_WARNING(true, ("debug_ai: Unable to get the ScriptObject for this object(%s)", m_aiShipController.getOwner()->getDebugInformation().c_str()));
}
}
}
}
// Move the ship
m_aiShipController.moveTo(goalPosition_w, throttle, deltaSeconds);
}
// ----------------------------------------------------------------------
bool AiShipBehaviorWaypoint::getNextPosition_w(Vector & position_w)
{
bool result = false;
SpacePath * const path = m_aiShipController.getPath();
if ( (path != NULL)
&& !path->isEmpty()
&& (m_aiShipController.getCurrentPathIndex() < path->getTransformList().size()))
{
ShipObject const * const shipObject = m_aiShipController.getShipOwner();
if (shipObject != NULL)
{
SpacePath::TransformList const & transformList = path->getTransformList();
Vector const & nextPosition = getGoalPosition_w();
float const distanceToGoalSquared = shipObject->getPosition_w().magnitudeBetweenSquared(nextPosition);
// If the distance to the goal position is less than a specified amount,
// the calculate the next position using a spline to round out the transition
// to the next point.
float const turnRadiusSquared = sqr(m_aiShipController.getLargestTurnRadius());
if (distanceToGoalSquared < turnRadiusSquared)
{
// Move to the next path point
if (m_cyclic)
{
if ((m_aiShipController.getCurrentPathIndex() + 1) >= transformList.size())
{
m_aiShipController.setCurrentPathIndex(0);
}
else
{
m_aiShipController.setCurrentPathIndex(m_aiShipController.getCurrentPathIndex() + 1);
}
}
else
{
if (m_aiShipController.getCurrentPathIndex() < (transformList.size() - 1))
{
m_aiShipController.setCurrentPathIndex(m_aiShipController.getCurrentPathIndex() + 1);
}
}
}
result = true;
position_w = getGoalPosition_w();
}
}
else
{
m_aiShipController.setCurrentPathIndex(0);
}
return result;
}
// ----------------------------------------------------------------------
Vector AiShipBehaviorWaypoint::getGoalPosition_w() const
{
Vector result;
SpacePath * const path = m_aiShipController.getPath();
if ( (path != NULL)
&& !path->isEmpty())
{
SpacePath::TransformList const & transformList = path->getTransformList();
result = transformList[m_aiShipController.getCurrentPathIndex()].getPosition_p();
m_aiShipController.clampPositionToZone(result);
}
else
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("AiShipBehaviorWaypoint::getGoalPosition_w() unit(%s) ERROR: Getting a goal position on an empty path.", m_aiShipController.getOwner()->getNetworkId().getValueString().c_str()));
}
return result;
}
//// ----------------------------------------------------------------------
//
//Vector AiShipBehaviorWaypoint::getPreviousGoalPosition() const
//{
// Vector result;
//
// if (!path.empty())
// {
// if ((m_currentPathIndex - 1) >= path.size())
// {
// result = path[path.size() - 1].getPosition_p();
// }
// else
// {
// result = path[m_currentPathIndex - 1].getPosition_p();
// }
// }
//
// return result;
//}
//
//// ----------------------------------------------------------------------
//
//Vector AiShipBehaviorWaypoint::getNextGoalPosition() const
//{
// Vector result;
//
// if (!path.empty())
// {
// if ((m_currentPathIndex + 1) >= path.size())
// {
// result = path[0].getPosition_p();
// }
// else
// {
// result = path[m_currentPathIndex + 1].getPosition_p();
// }
// }
//
// return result;
//}
// ----------------------------------------------------------------------
AiShipBehaviorType AiShipBehaviorWaypoint::getBehaviorType() const
{
AiShipBehaviorType result = ASBT_moveTo;
if (m_cyclic)
{
result = ASBT_patrol;
}
return result;
}
#ifdef _DEBUG
// ----------------------------------------------------------------------
void AiShipBehaviorWaypoint::addDebug(AiDebugString & aiDebugString)
{
if (m_aiShipController.isSquadLeader())
{
SpacePath const * const path = m_aiShipController.getPath();
if (path != NULL)
{
aiDebugString.addLineToPosition(m_aiShipController.getMoveToGoalPosition_w(), PackedRgb::solidGreen);
aiDebugString.addCircle(m_aiShipController.getMoveToGoalPosition_w(), m_aiShipController.getLargestTurnRadius(), PackedRgb::solidGreen);
aiDebugString.addPath(path->getTransformList(), m_cyclic);
char const * const text = FormattedString<256>().sprintf("%s [PATH SIZE %u]\n", getBehaviorString(getBehaviorType()), path->getTransformList().size());
aiDebugString.addText(text, PackedRgb::solidCyan);
}
else
{
char const * const text = FormattedString<256>().sprintf("%s [ERROR: NO PATH]\n", getBehaviorString(getBehaviorType()));
aiDebugString.addText(text, PackedRgb::solidCyan);
}
}
else
{
AiShipBehaviorBase::addDebug(aiDebugString);
}
}
#endif // _DEBUG
// ======================================================================
@@ -0,0 +1,52 @@
// ======================================================================
//
// AiShipBehaviorWaypoint.h
// Copyright 2004 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AiShipBehaviorWaypoint_H
#define INCLUDED_AiShipBehaviorWaypoint_H
#include "serverGame/AiShipBehaviorBase.h"
class AiDebugString;
class AiShipController;
class Vector;
// ======================================================================
class AiShipBehaviorWaypoint : public AiShipBehaviorBase
{
public:
AiShipBehaviorWaypoint(AiShipController & aiShipController, bool const cyclic);
virtual void alter(float deltaSeconds);
virtual AiShipBehaviorType getBehaviorType() const;
#ifdef _DEBUG
virtual void addDebug(AiDebugString & aiDebugString);
#endif // _DEBUG
private:
bool getNextPosition_w(Vector & position_w);
Vector getGoalPosition_w() const;
//Vector getPreviousGoalPosition() const;
//Vector getNextGoalPosition() const;
bool m_cyclic;
bool m_moveToCompleteTriggerSent;
// Disabled
AiShipBehaviorWaypoint();
AiShipBehaviorWaypoint(AiShipBehaviorWaypoint const &);
AiShipBehaviorWaypoint &operator =(AiShipBehaviorWaypoint const &);
};
// ======================================================================
#endif // INCLUDED_AiShipBehaviorWaypoint_H
@@ -0,0 +1,42 @@
// ======================================================================
//
// AiShipTurretTargetingSystem.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/AiShipTurretTargetingSystem.h"
#include "serverGame/ShipObject.h"
// ======================================================================
AiShipTurretTargetingSystem::AiShipTurretTargetingSystem(ShipController & shipController) :
ShipTurretTargetingSystem(shipController)
{
}
// ----------------------------------------------------------------------
AiShipTurretTargetingSystem::~AiShipTurretTargetingSystem()
{
}
// ----------------------------------------------------------------------
void AiShipTurretTargetingSystem::doShot(int const weaponIndex, NetworkId const & targetId, ShipChassisSlotType::Type targetedComponent, bool const goodShot)
{
PROFILER_AUTO_BLOCK_DEFINE("AiShipTurretTargetingSystem::doShot");
ShipObject & shipObject = getShipOwner();
shipObject.fireShotTurretServer(weaponIndex, targetId, targetedComponent, goodShot, false);
}
// ----------------------------------------------------------------------
bool AiShipTurretTargetingSystem::isTurretControlled(int const /*weaponIndex*/)
{
return true;
}
// ======================================================================
@@ -0,0 +1,43 @@
// ======================================================================
//
// AiShipTurretTargetingSystem.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_AiShipTurretTargetingSystem_H
#define INCLUDED_AiShipTurretTargetingSystem_H
// ======================================================================
#include "serverGame/AiShipAttackTargetList.h"
#include "serverGame/ShipTurretTargetingSystem.h"
#include "sharedFoundation/Timer.h"
class AiShipController;
class CachedNetworkId;
class NetworkId;
// ======================================================================
/**
* Fire AI turrets automatically at enemies.
*/
class AiShipTurretTargetingSystem : public ShipTurretTargetingSystem
{
public:
AiShipTurretTargetingSystem(ShipController & shipController);
virtual ~AiShipTurretTargetingSystem();
private:
virtual void doShot(int const weaponIndex, NetworkId const & targetId, ShipChassisSlotType::Type targetedComponent, bool const goodShot);
virtual bool isTurretControlled(int const weaponIndex);
private:
AiShipTurretTargetingSystem(AiShipTurretTargetingSystem const &); //disable
AiShipTurretTargetingSystem& operator=(AiShipTurretTargetingSystem const &); //disable
};
// ======================================================================
#endif
@@ -0,0 +1,59 @@
// ======================================================================
//
// PlayerShipTurretTargetingSystem.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/PlayerShipTurretTargetingSystem.h"
#include "serverGame/ShipObject.h"
// ======================================================================
PlayerShipTurretTargetingSystem::PlayerShipTurretTargetingSystem(ShipController & shipController) :
ShipTurretTargetingSystem(shipController),
m_playerControlledWeaponIndices(new BitArray)
{
}
// ----------------------------------------------------------------------
PlayerShipTurretTargetingSystem::~PlayerShipTurretTargetingSystem()
{
delete m_playerControlledWeaponIndices;
}
// ----------------------------------------------------------------------
void PlayerShipTurretTargetingSystem::doShot(int const weaponIndex, NetworkId const & targetId, ShipChassisSlotType::Type targetedComponent, bool const goodShot)
{
ShipObject & shipObject = getShipOwner();
shipObject.fireShotTurretServer(weaponIndex, targetId, targetedComponent, goodShot, true);
}
// ----------------------------------------------------------------------
bool PlayerShipTurretTargetingSystem::isTurretControlled(int const weaponIndex)
{
return !m_playerControlledWeaponIndices->testBit(weaponIndex);
}
// ----------------------------------------------------------------------
void PlayerShipTurretTargetingSystem::setWeaponIndexPlayerControlled(int const weaponIndex, bool const playerControlled)
{
DEBUG_FATAL((weaponIndex < 0), ("Invalid weaponIndex(%d)", weaponIndex));
if (playerControlled)
{
m_playerControlledWeaponIndices->setBit(weaponIndex);
}
else
{
m_playerControlledWeaponIndices->clearBit(weaponIndex);
}
}
// ======================================================================
@@ -0,0 +1,47 @@
// ======================================================================
//
// PlayerShipTurretTargetingSystem.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PlayerShipTurretTargetingSystem_H
#define INCLUDED_PlayerShipTurretTargetingSystem_H
// ======================================================================
#include "serverGame/ShipTurretTargetingSystem.h"
class AiShipController;
class BitArray;
class CachedNetworkId;
class NetworkId;
// ======================================================================
/**
* Automatically fire some or all of the player's ship's turrets
*/
class PlayerShipTurretTargetingSystem : public ShipTurretTargetingSystem
{
public:
PlayerShipTurretTargetingSystem(ShipController & shipController);
virtual ~PlayerShipTurretTargetingSystem();
void setWeaponIndexPlayerControlled(int const weaponIndex, bool const playerControlled);
private:
virtual void doShot(int const weaponIndex, NetworkId const & targetId, ShipChassisSlotType::Type targetedComponent, bool const goodShot);
virtual bool isTurretControlled(int const weaponIndex);
private:
BitArray * const m_playerControlledWeaponIndices;
private:
PlayerShipTurretTargetingSystem(PlayerShipTurretTargetingSystem const &); //disable
PlayerShipTurretTargetingSystem& operator=(PlayerShipTurretTargetingSystem const &); //disable
};
// ======================================================================
#endif
@@ -0,0 +1,276 @@
// ======================================================================
//
// ShipTurretTargetingSystem.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/ShipTurretTargetingSystem.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ShipController.h"
#include "serverGame/ShipObject.h"
#include "sharedLog/Log.h"
// ======================================================================
ShipTurretTargetingSystem::ShipTurretTargetingSystem(ShipController & shipController) :
m_targetsDirty(false),
m_shipController(shipController),
m_turretsPerTarget(new TurretsPerTargetType),
m_targetList(new AiShipAttackTargetList::SortedTargetList),
m_idealTurretsPerTarget(0),
m_retargetTimer(2.0f) //TODO: determine if we need really this. It was done because SpaceTargetManager::buildTargetList is expensive and we don't want to call it often, but that may change
{
}
// ----------------------------------------------------------------------
ShipTurretTargetingSystem::~ShipTurretTargetingSystem()
{
delete m_turretsPerTarget;
delete m_targetList;
}
// ---------------------------------------------------------------------
void ShipTurretTargetingSystem::alter(float const deltaTime)
{
PROFILER_AUTO_BLOCK_DEFINE("ShipTurretTargetingSystem::alter");
IGNORE_RETURN(m_retargetTimer.updateNoReset(deltaTime));
ShipObject * const shipObject = NON_NULL(NON_NULL(NON_NULL(m_shipController.getOwner())->asServerObject())->asShipObject());
for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex)
{
if (shipObject->isTurret(weaponIndex)
&& isTurretControlled(weaponIndex))
{
PROFILER_AUTO_BLOCK_DEFINE("turret");
bool canFireShot = false;
Object const * const target = shipObject->getTurretTarget(weaponIndex).getObject();
if (target)
{
Vector const & turretPosition_w = shipObject->getTurretTransform(weaponIndex).getPosition_p();
bool const targetInRange = (target->getPosition_w().magnitudeBetweenSquared(turretPosition_w) <= sqr(shipObject->getWeaponRange(weaponIndex)));
if (targetInRange)
{
canFireShot = shipObject->canTurretFireTowardsLocation_p(weaponIndex, target->getPosition_w());
if (canFireShot)
{
ShipChassisSlotType::Type const shipChassisSlotType = static_cast<ShipChassisSlotType::Type>(static_cast<int>(ShipChassisSlotType::SCST_weapon_0) + weaponIndex);
if (shipObject->isSlotInstalled(shipChassisSlotType))
{
if (shipObject->hasEnergyForAShot(weaponIndex) && shipObject->hasAmmoForAShot(weaponIndex))
{
PROFILER_AUTO_BLOCK_DEFINE("fireShot");
doShot(weaponIndex, target->getNetworkId(), shipObject->getPilotLookAtTargetSlot(), (Random::randomReal(0.0f,1.0f) > m_shipController.getTurretMissChance()));
// Keep my target in my attack target list, this resets the decay timer for the unit we are attacking, so it is not purged from the attack target list
NetworkId const & attackingUnit = target->getNetworkId();
float const damage = 0.0001f;
bool const verifyAttacker = false;
m_shipController.addDamageTaken(attackingUnit, damage, verifyAttacker);
}
}
}
}
}
if (!canFireShot)
{
shipObject->setTurretTarget(weaponIndex, onTurretLostTarget(weaponIndex, shipObject->getTurretTarget(weaponIndex)));
}
}
}
}
// ----------------------------------------------------------------------
ShipController const & ShipTurretTargetingSystem::getShipController() const
{
return m_shipController;
}
// ----------------------------------------------------------------------
ShipController & ShipTurretTargetingSystem::getShipController()
{
return m_shipController; //lint !e1536 // returning reference to member
}
// ----------------------------------------------------------------------
void ShipTurretTargetingSystem::onTargetChanged(NetworkId const & /*target*/)
{
m_targetsDirty = true;
}
// ----------------------------------------------------------------------
void ShipTurretTargetingSystem::onTargetLost(NetworkId const & target)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipTurretTargetingSystem::onTargetLost() owner(%s) target(%s)", m_shipController.getOwner()->getNetworkId().getValueString().c_str(), target.getValueString().c_str()));
m_targetsDirty = true;
// If any turret was attacking this target, remove the target
ShipObject * const shipObject = NON_NULL(NON_NULL(NON_NULL(m_shipController.getOwner())->asServerObject())->asShipObject());
if (!shipObject) // for release builds
{
WARNING(true,("Programmer bug: got a NULL ShipObject in ShipTurretTargetingSystem::onTargetLost(). May indicate that the ShipObject has already been partially deconstructed."));
return;
}
for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex)
{
if (shipObject->isTurret(weaponIndex))
{
if (shipObject->getTurretTarget(weaponIndex) == target)
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipTurretTargetingSystem::onTargetLost() owner(%s) TARGET LOST(%s)", m_shipController.getOwner()->getNetworkId().getValueString().c_str(), target.getValueString().c_str()));
// Remove the turrets assignment since it is no longer in the target list
shipObject->setTurretTarget(weaponIndex, CachedNetworkId::cms_cachedInvalid);
}
}
}
// We must acquire a new target list here so the turrets stop shooting at invalid targets
IGNORE_RETURN(buildTargetList());
}
// ----------------------------------------------------------------------
ShipObject & ShipTurretTargetingSystem::getShipOwner()
{
return (*NON_NULL(NON_NULL(NON_NULL(m_shipController.getOwner())->asServerObject())->asShipObject()));
}
// ----------------------------------------------------------------------
bool ShipTurretTargetingSystem::buildTargetList()
{
m_retargetTimer.reset();
m_targetsDirty = false;
// Get a new list of attack targets
ShipObject * const ownerShipObject = getShipController().getShipOwner();
ShipController * const ownerShipController = ownerShipObject->getController()->asShipController();
bool result = false;
m_targetList->clear();
if (ownerShipController != NULL)
{
if (!ownerShipController->getAttackTargetList().isEmpty())
{
result = true;
ownerShipController->getAttackTargetList().getSortedTargetList(*m_targetList);
// Count the number of turrets currently available
int numGuns=0;
for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex)
{
if (ownerShipObject->isTurret(weaponIndex))
{
ShipChassisSlotType::Type const shipChassisSlotType = static_cast<ShipChassisSlotType::Type>(static_cast<int>(ShipChassisSlotType::SCST_weapon_0) + weaponIndex);
if (ownerShipObject->isSlotInstalled(shipChassisSlotType))
++numGuns;
}
}
m_idealTurretsPerTarget = std::max(1, numGuns / static_cast<int>(m_targetList->size()));
}
else
{
m_idealTurretsPerTarget = 0;
}
}
else
{
LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("PlayerShipTurretTargetingSystem::alter() ERROR: Why does this owner(%s) not have an ShipController?", ownerShipObject->getNetworkId().getValueString().c_str()));
}
// Cleanup: remove anything from the turretsPerTarget that has a count of 0, so that turretsPerTarget doesn't grow indefinitely
for (TurretsPerTargetType::iterator i=m_turretsPerTarget->begin(); i!=m_turretsPerTarget->end();)
{
if (i->second <= 0)
m_turretsPerTarget->erase(i++);
else
++i;
}
return result;
}
// ----------------------------------------------------------------------
/**
* Called when a turret has no target or can't shoot at its assigned target.
* Figure out a new target for the turret.
*/
CachedNetworkId ShipTurretTargetingSystem::onTurretLostTarget(int const weaponIndex, CachedNetworkId const & oldTarget)
{
// Only get new targets if some new targets have been added to the list while the timer was ticking
if ( m_targetsDirty
&& m_retargetTimer.isExpired()
&& !buildTargetList())
{
return CachedNetworkId::cms_cachedInvalid;
}
if (oldTarget != CachedNetworkId::cms_cachedInvalid)
{
--((*m_turretsPerTarget)[oldTarget]);
DEBUG_FATAL((*m_turretsPerTarget)[oldTarget] < 0,("Programmer bug: m_turretsPerTarget went negative for target %s", oldTarget.getValueString().c_str()));
}
ShipObject * const ownerShipObject = getShipController().getShipOwner();
CachedNetworkId bestTarget(CachedNetworkId::cms_cachedInvalid);
CachedNetworkId bestTargetIgnoringLimits(CachedNetworkId::cms_cachedInvalid);
for (AiShipAttackTargetList::SortedTargetList::const_iterator target = m_targetList->begin(); target != m_targetList->end(); ++target)
{
CachedNetworkId const & cachedNetworkId = target->first;
Object const * const targetObject = NON_NULL(cachedNetworkId.getObject());
if (targetObject)
{
if (ownerShipObject->canTurretFireTowardsLocation_p(weaponIndex, targetObject->getPosition_w()))
{
if ((*m_turretsPerTarget)[target->first] < m_idealTurretsPerTarget)
{
bestTarget = target->first;
break;
}
else
bestTargetIgnoringLimits = target->first;
}
}
}
if (bestTarget == CachedNetworkId::cms_cachedInvalid)
bestTarget = bestTargetIgnoringLimits;
if (bestTarget != CachedNetworkId::cms_cachedInvalid)
{
++((*m_turretsPerTarget)[bestTarget]);
return bestTarget;
}
return CachedNetworkId::cms_cachedInvalid;
}
// ======================================================================
@@ -0,0 +1,75 @@
// ======================================================================
//
// ShipTurretTargetingSystem.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_ShipTurretTargetingSystem_H
#define INCLUDED_ShipTurretTargetingSystem_H
// ======================================================================
#include "serverGame/AiShipAttackTargetList.h"
#include "sharedFoundation/Timer.h"
#include "sharedGame/ShipChassisSlotType.h"
class CachedNetworkId;
class NetworkId;
class ShipController;
class ShipObject;
// ======================================================================
/**
* A system that automatically fires ship turrets at enemies.
* This can be attached to a ship controller, which will cause
* the ship to automatically fire its turrets.
*
* Derive from this class to make targeting systems for AI or for player
* ships with autopilot.
*/
class ShipTurretTargetingSystem
{
public:
ShipTurretTargetingSystem(ShipController & shipController);
virtual ~ShipTurretTargetingSystem() = 0;
virtual void alter(float const deltaTime);
ShipController const & getShipController() const;
ShipController & getShipController();
ShipObject & getShipOwner();
void clearTargets();
void onTargetChanged(NetworkId const & target);
void onTargetLost(NetworkId const & target);
protected:
bool m_targetsDirty;
private:
CachedNetworkId onTurretLostTarget(int const weaponIndex, CachedNetworkId const & oldTarget);
virtual void doShot(int const weaponIndex, NetworkId const & targetId, ShipChassisSlotType::Type targetedComponent, bool const goodShot) = 0;
virtual bool isTurretControlled(int const weaponIndex) = 0;
bool buildTargetList();
protected:
typedef stdmap<NetworkId, int>::fwd TurretsPerTargetType;
private:
ShipController & m_shipController;
protected:
TurretsPerTargetType * const m_turretsPerTarget;
AiShipAttackTargetList::SortedTargetList * const m_targetList;
int m_idealTurretsPerTarget;
Timer m_retargetTimer;
private:
ShipTurretTargetingSystem(ShipTurretTargetingSystem const &); //disable
ShipTurretTargetingSystem & operator=(ShipTurretTargetingSystem const &); //disable
};
// ======================================================================
#endif