mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-10-10 00:12:56 -04:00
Added serverGame library
This commit is contained in:
@@ -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
|
||||
+38
@@ -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");
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+37
@@ -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
|
||||
+1126
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
+746
@@ -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);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+112
@@ -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
|
||||
+259
@@ -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());
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+67
@@ -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
|
||||
+59
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+47
@@ -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
|
||||
Reference in New Issue
Block a user