// ====================================================================== // // ShipController.cpp // Copyright 2003 Sony Online Entertainment // // ====================================================================== #include "serverGame/FirstServerGame.h" #include "serverGame/ShipController.h" #include "serverGame/AiServerShipObjectInterface.h" #include "serverGame/AiShipAttackTargetList.h" #include "serverGame/AiShipBehaviorDock.h" #include "serverGame/AiShipController.h" #include "serverGame/ConfigServerGame.h" #include "serverGame/CreatureObject.h" #include "serverGame/PlayerShipTurretTargetingSystem.h" #include "serverGame/ServerShipObjectInterface.h" #include "serverGame/ShipObject.h" #include "serverGame/ShipTurretTargetingSystem.h" #include "sharedGame/ShipDynamicsModel.h" #include "sharedLog/Log.h" #include "sharedMathArchive/TransformArchive.h" #include "sharedNetworkMessages/MessageQueueGenericValueType.h" #include "sharedNetworkMessages/MessageQueueNetworkId.h" #include "sharedNetworkMessages/ShipUpdateTransformMessage.h" #include "sharedObject/NetworkIdManager.h" #include // ====================================================================== // // ShipControllerNamespace // // ====================================================================== namespace ShipControllerNamespace { typedef std::vector PurgeList; static PurgeList s_purgeList; time_t const s_maxTargetAge = 60 * 2; // If we are less than 5 degrees from the target orientation, don't roll. // This prevents "wobbling." float const s_fastOrientationDeltaRadians = convertDegreesToRadians(5.0f); } using namespace ShipControllerNamespace; // ====================================================================== // PUBLIC ShipController // ====================================================================== ShipController::ShipController(ShipObject * newOwner) : TangibleController(newOwner), m_shipDynamicsModel(new ShipDynamicsModel), m_yawPosition(0.0f), m_pitchPosition(0.0f), m_rollPosition(0.0f), m_throttlePosition(0.0f), m_pendingDockingBehavior(NULL), m_dockingBehavior(NULL), m_attackTargetList(new AiShipAttackTargetList(newOwner)), m_attackTargetDecayTimer(new Timer(static_cast(s_maxTargetAge))), m_enemyCheckQueued(false), m_turretTargetingSystem(NULL), m_dockedByList(new DockedByList), m_aiTargetingMeList(new CachedNetworkIdList) { m_attackTargetDecayTimer->setElapsedTime(Random::randomReal() * m_attackTargetDecayTimer->getExpireTime()); } // ---------------------------------------------------------------------- ShipController::~ShipController() { // The turret targeting system must be deleted before clearAiTargetingMeList(), because // otherwise it will try to acquire new targets as the list is being cleared delete m_turretTargetingSystem; m_turretTargetingSystem = NULL; clearAiTargetingMeList(); delete m_shipDynamicsModel; delete m_dockedByList; delete m_aiTargetingMeList; delete m_pendingDockingBehavior; m_pendingDockingBehavior = NULL; delete m_dockingBehavior; m_dockingBehavior = NULL; delete m_attackTargetList; delete m_attackTargetDecayTimer; } // ---------------------------------------------------------------------- void ShipController::endBaselines() { Object const * const owner = getOwner(); if (owner) { m_shipDynamicsModel->setTransform(owner->getTransform_o2p()); m_shipDynamicsModel->makeStationary(); } TangibleController::endBaselines(); } // ---------------------------------------------------------------------- void ShipController::teleport(Transform const &goal, ServerObject *goalObj) { if (!goalObj) m_shipDynamicsModel->setTransform(goal); TangibleController::teleport(goal, goalObj); } // ---------------------------------------------------------------------- void ShipController::onAddedToWorld() { Object const * const owner = getOwner(); if (owner) { m_shipDynamicsModel->setTransform(owner->getTransform_o2p()); m_shipDynamicsModel->makeStationary(); } } // ---------------------------------------------------------------------- Transform const &ShipController::getTransform() const { return m_shipDynamicsModel->getTransform(); } // ---------------------------------------------------------------------- Vector const &ShipController::getVelocity() const { return m_shipDynamicsModel->getVelocity(); } // ---------------------------------------------------------------------- float ShipController::getSpeed() const { return m_shipDynamicsModel->getSpeed(); } // ---------------------------------------------------------------------- float ShipController::getYawRate() const { return m_shipDynamicsModel->getYawRate(); } // ---------------------------------------------------------------------- float ShipController::getPitchRate() const { return m_shipDynamicsModel->getPitchRate(); } // ---------------------------------------------------------------------- float ShipController::getRollRate() const { return m_shipDynamicsModel->getRollRate(); } // ---------------------------------------------------------------------- void ShipController::respondToCollision(Vector const & deltaToMove_p, Vector const & newReflection_p, Vector const & /* normalOfSurface_p */) { // this is identical to the clients ShipController::respondToCollision. // the difference it that the server also must call the virtual method // ShipController::experiencedCollision at the end of execution Transform transform_p(m_shipDynamicsModel->getTransform()); transform_p.move_p(deltaToMove_p); m_shipDynamicsModel->setTransform(transform_p); m_shipDynamicsModel->setVelocity(newReflection_p * m_shipDynamicsModel->getVelocity().magnitude()); ShipObject * const owner = getShipOwner(); NOT_NULL(owner); owner->setTransform_o2p(transform_p); experiencedCollision(); } // ---------------------------------------------------------------------- float ShipController::realAlter(float elapsedTime) { PROFILER_AUTO_BLOCK_DEFINE("ShipController::realAlter"); ShipObject const * const owner = getShipOwner(); if (owner->isInWorld()) { if (m_turretTargetingSystem) { m_turretTargetingSystem->alter(elapsedTime); } // Decay the attack targets if (m_attackTargetDecayTimer->updateZero(elapsedTime)) { PROFILER_AUTO_BLOCK_DEFINE("attackTargetList"); m_attackTargetList->purge(s_maxTargetAge); if (m_attackTargetList->isEmpty()) { onAttackTargetListEmpty(); } } } return TangibleController::realAlter(elapsedTime); } // ---------------------------------------------------------------------- void ShipController::handleMessage (const int message, const float value, const MessageQueue::Data* const data, const uint32 flags) { UNREF(flags); UNREF(value); ShipObject * const owner = getShipOwner(); DEBUG_FATAL(!owner, ("Owner is NULL in ShipController::handleMessage\n")); switch(message) { case CM_clientLookAtTarget: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); owner->setPilotLookAtTarget (msg->getNetworkId ()); } break; case CM_clientLookAtTargetComponent: { const MessageQueueGenericValueType * const msg = NON_NULL (dynamic_cast *>(data)); owner->setPilotLookAtTargetSlot (static_cast(msg->getValue())); } break; default: ServerController::handleMessage(message, value, data, flags); break; } } // ---------------------------------------------------------------------- void ShipController::addTurretTargetingSystem(ShipTurretTargetingSystem * newSystem) { DEBUG_FATAL(&newSystem->getShipController() != this,("Programmer bug: called addTurretTargetingSystem with a ShipTurretTargetingSystem whose owner did not match the controller it tried to attach to.")); removeTurretTargetingSystem(); m_turretTargetingSystem = newSystem; } // ---------------------------------------------------------------------- void ShipController::removeTurretTargetingSystem() { delete m_turretTargetingSystem; m_turretTargetingSystem = NULL; } // ---------------------------------------------------------------------- bool ShipController::isBeingDocked() const { return !m_dockedByList->empty(); } // ---------------------------------------------------------------------- void ShipController::addDockedBy(Object const & unit) { IGNORE_RETURN(m_dockedByList->insert(CachedNetworkId(unit))); LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::addDockedBy() owner(%s) dockedBy(%s) dockedByListSize(%u)", (getOwner() != NULL) ? getOwner()->getNetworkId().getValueString().c_str() : "NULL", unit.getNetworkId().getValueString().c_str(), m_dockedByList->size())); } // ---------------------------------------------------------------------- void ShipController::removeDockedBy(Object const & unit) { DockedByList::iterator iterDockedByList = m_dockedByList->find(CachedNetworkId(unit)); if (iterDockedByList != m_dockedByList->end()) { m_dockedByList->erase(iterDockedByList); LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::removeDockedBy() owner(%s) dockedBy(%s) dockedByListSize(%u)", (getOwner() != NULL) ? getOwner()->getNetworkId().getValueString().c_str() : "NULL", unit.getNetworkId().getValueString().c_str(), m_dockedByList->size())); } else { DEBUG_WARNING(true, ("debug_ai: ERROR: Trying to remove a docking unit(%s) that is not actually in the process of docking.", unit.getDebugInformation().c_str())); } } // ---------------------------------------------------------------------- ShipController::DockedByList const & ShipController::getDockedByList() const { return *m_dockedByList; } // ---------------------------------------------------------------------- void ShipController::addAiTargetingMe(NetworkId const & unit) { //LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::addAiTargetingMe() owner(%s) unit(%s) m_aiTargetingMeList->size(%u+1)", getOwner()->getNetworkId().getValueString().c_str(), unit.getValueString().c_str(), m_aiTargetingMeList->size())); DEBUG_FATAL((NetworkIdManager::getObjectById(unit) == NULL), ("ShipController::addAiTargetingMe() owner(%s) unit(%s) ERROR: The Ai who is targeting you is not a valid networkId", getOwner()->getNetworkId().getValueString().c_str(), unit.getValueString().c_str())); // Make sure this is a valid networkId of an alive object IGNORE_RETURN(m_aiTargetingMeList->insert(CachedNetworkId(unit))); } // ---------------------------------------------------------------------- void ShipController::removeAiTargetingMe(NetworkId const & unit) { //LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::removeAiTargetingMe() owner(%s) unit(%s) m_aiTargetingMeList->size(%u-1)", getOwner()->getNetworkId().getValueString().c_str(), unit.getValueString().c_str(), m_aiTargetingMeList->size())); CachedNetworkIdList::iterator iterTargetByList = m_aiTargetingMeList->find(CachedNetworkId(unit)); if (iterTargetByList != m_aiTargetingMeList->end()) { m_aiTargetingMeList->erase(iterTargetByList); } else { // If you hit this fatal, then there is an removeAiTargetingMe() called without a matching addAiTargetingMe(). DEBUG_FATAL(true, ("Unable to find unit.")); } // If no one else is targeting me (player's only), stop combat music if (m_aiTargetingMeList->empty()) { ShipObject * const shipOwner = getShipOwner(); if (shipOwner != NULL) { CreatureObject * const pilotOwner = CreatureObject::asCreatureObject(shipOwner->getPilot()); if ( (pilotOwner != NULL) && pilotOwner->isPlayerControlled()) { shipOwner->clearCondition(static_cast(TangibleObject::C_spaceCombatMusic)); //LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::removeAiTargetingMe() owner(%s) Clearing TangibleObject::C_spaceCombatMusic", getOwner()->getNetworkId().getValueString().c_str())); } } } } // ---------------------------------------------------------------------- ShipController::CachedNetworkIdList const & ShipController::getAiTargetingMeList() const { return *m_aiTargetingMeList; } // ---------------------------------------------------------------------- void ShipController::setPosition_w(Vector const & position, bool const allowOrientation) { Transform transform(m_shipDynamicsModel->getTransform()); transform.setPosition_p(position); m_shipDynamicsModel->setTransform(transform); if (allowOrientation) { m_shipDynamicsModel->stop(); } else { m_shipDynamicsModel->makeStationary(); } } // ---------------------------------------------------------------------- bool ShipController::face(Vector const & goalPosition_w, float elapsedTime) { //DEBUG_REPORT_LOG(true, ("ShipController::face() owner(%s)\n", getOwner()->getNetworkId().getValueString().c_str())); ShipObject * const shipObject = NON_NULL(getShipOwner()); ServerShipObjectInterface const shipInterface(shipObject); Transform shipTransform = shipObject->getTransform_o2w(); bool reachedYaw = false; bool reachedPitch = false; if (shipInterface.getMaximumYaw() > 0.f) { Vector const goal_o = shipTransform.rotateTranslate_p2l(goalPosition_w); float const goalYaw = goal_o.theta(); float const goalYawRate = goalYaw / elapsedTime; float const maxYawRate = shipInterface.getMaximumYaw(); if((goalYawRate >= -maxYawRate) && (goalYawRate <= maxYawRate)) reachedYaw = true; float const actualYawRate = clamp(-maxYawRate, goalYawRate, maxYawRate); float const actualYaw = actualYawRate * elapsedTime; m_yawPosition = actualYawRate / maxYawRate; shipTransform.yaw_l(actualYaw); } if (shipInterface.getMaximumPitch() > 0.f) { Vector const goal_o = shipTransform.rotateTranslate_p2l(goalPosition_w); float const goalPitch = goal_o.phi(); float const goalPitchRate = goalPitch / elapsedTime; float const maxPitchRate = shipInterface.getMaximumPitch(); if((goalPitchRate >= -maxPitchRate) && (goalPitchRate <= maxPitchRate)) reachedPitch = true; float const actualPitchRate = clamp(-maxPitchRate, goalPitchRate, maxPitchRate); float const actualPitch = actualPitchRate * elapsedTime; m_pitchPosition = actualPitchRate / maxPitchRate; shipTransform.pitch_l(actualPitch); } // If enabled, rotate on the "fast" axis of the ship. bool isRollSet = false; if (AiServerShipObjectInterface::isFastAxisEnabled()) { bool useFastAxis = true; AiShipController const * const aiShipController = asAiShipController(); if (aiShipController != NULL) { if ( (aiShipController->getShipClass() == ShipAiReactionManager::SC_capitalShip) || (aiShipController->getShipClass() == ShipAiReactionManager::SC_transport) || !aiShipController->isAttacking()) { useFastAxis = false; } } if (useFastAxis) { Vector desiredOrientation(m_pitchPosition, m_yawPosition, 0.0f); Vector fastOrientation(shipInterface.getMaximumPitch(), shipInterface.getMaximumYaw(), 0.0f); // Validate the normalized vectors and rotate along fast axis iff the vectors differ significantly. if (desiredOrientation.normalize() && fastOrientation.normalize() && ((desiredOrientation.dot(fastOrientation) + s_fastOrientationDeltaRadians) < 1.0f)) { Vector const & targetOrientation = desiredOrientation.cross(fastOrientation); m_rollPosition = clamp(-1.0f, targetOrientation.z, 1.0f); isRollSet = true; } } } // If the roll wasn't set, use the original roll calculation. if (!isRollSet && shipInterface.getMaximumRoll() > 0.f) { Vector const goal_o = shipTransform.rotateTranslate_p2l(goalPosition_w); float goalRoll = 0.f; float const d = sqrt(sqr(goal_o.x) + sqr(goal_o.y)); float const phi = atan2(d,goal_o.z); if(phi > convertDegreesToRadians(10.f)) { goalRoll = -atan2(goal_o.x,goal_o.y); } else { // if we're not trying to align with the target, try to align with the Y axis, // but only if we're not heading nearly straight up or down Vector const upPoint_w = shipTransform.getPosition_p() + Vector::unitY; Vector const upPoint_o = shipTransform.rotateTranslate_p2l(upPoint_w); float d2 = sqrt(sqr(upPoint_o.x) + sqr(upPoint_o.y)); float phi2 = atan2(d2,std::abs(upPoint_o.z)); if(phi2 > convertDegreesToRadians(10.f)) { goalRoll = -atan2(upPoint_o.x,upPoint_o.y); } } float const goalRollRate = goalRoll / elapsedTime; float const maxRollRate = shipInterface.getMaximumRoll(); float const actualRollRate = clamp(-maxRollRate, goalRollRate, maxRollRate); //float const actualRoll = actualRollRate * elapsedTime; m_rollPosition = actualRollRate / maxRollRate; } return reachedYaw && reachedPitch; } // ---------------------------------------------------------------------- bool ShipController::face(Vector const & goalPosition_w, Vector const & up_w, float const elapsedTime) { //DEBUG_REPORT_LOG(true, ("ShipController::face(up_w) owner(%s)\n", getOwner()->getNetworkId().getValueString().c_str())); ShipObject * const shipObject = NON_NULL(getShipOwner()); ServerShipObjectInterface const shipInterface(shipObject); Transform shipTransform(shipObject->getTransform_o2w()); // Yaw bool reachedYaw = false; { if (shipInterface.getMaximumYaw() > 0.f) { Vector const goal_o = shipTransform.rotateTranslate_p2l(goalPosition_w); float const goalYaw = goal_o.theta(); float const goalYawRate = goalYaw / elapsedTime; float const maxYawRate = shipInterface.getMaximumYaw(); if((goalYawRate >= -maxYawRate) && (goalYawRate <= maxYawRate)) reachedYaw = true; float const actualYawRate = clamp(-maxYawRate, goalYawRate, maxYawRate); float const actualYaw = actualYawRate * elapsedTime; m_yawPosition = actualYawRate / maxYawRate; shipTransform.yaw_l(actualYaw); } } // Pitch bool reachedPitch = false; { if (shipInterface.getMaximumPitch() > 0.f) { Vector const goal_o = shipTransform.rotateTranslate_p2l(goalPosition_w); float const goalPitch = goal_o.phi(); float const goalPitchRate = goalPitch / elapsedTime; float const maxPitchRate = shipInterface.getMaximumPitch(); if((goalPitchRate >= -maxPitchRate) && (goalPitchRate <= maxPitchRate)) reachedPitch = true; float const actualPitchRate = clamp(-maxPitchRate, goalPitchRate, maxPitchRate); float const actualPitch = actualPitchRate * elapsedTime; m_pitchPosition = actualPitchRate / maxPitchRate; shipTransform.pitch_l(actualPitch); } } // Roll bool reachedRoll = false; { float const maxRollRate = shipInterface.getMaximumRoll(); if (maxRollRate > 0.f) { Vector goalUp_o = shipTransform.rotateTranslate_p2l(up_w); goalUp_o.normalize(); float const dot = Vector::unitY.dot(goalUp_o); float const angleBetween = acos(dot); if ( (goalUp_o.y > 0.0f) && (angleBetween < convertDegreesToRadians(1.0f))) { m_rollPosition = 0.0f; reachedRoll = true; } else if (goalUp_o.x > 0.0f) { m_rollPosition = -1.0f; } else if (goalUp_o.x < 0.0f) { m_rollPosition = 1.0f; } if ( (m_rollPosition > 0.0f) || (m_rollPosition < 0.0f)) { float const goalRollRate = angleBetween * elapsedTime * 10.0f; float const actualRollRate = clamp(-maxRollRate, goalRollRate, maxRollRate); m_rollPosition *= actualRollRate / maxRollRate; } } } return reachedYaw && reachedPitch && reachedRoll; } // ---------------------------------------------------------------------- void ShipController::setThrottle(float throttle) { m_throttlePosition = clamp(0.0f,throttle,1.0f); } // ---------------------------------------------------------------------- float ShipController::getLargestTurnRadius() const { float result = 0.0f; ShipObject const * const shipObject = getShipOwner(); if (shipObject != NULL) { float const maxYawRate = shipObject->getShipActualYawRateMaximum(); float const maxPitchRate = shipObject->getShipActualPitchRateMaximum(); float const maxRollRate = shipObject->getShipActualRollRateMaximum(); float const maxTurnRate = std::min(std::min(maxYawRate, maxPitchRate), maxRollRate); float const speedMaximum = shipObject->getShipActualSpeedMaximum(); result = (maxTurnRate > 0.0f) ? (speedMaximum / maxTurnRate) : 0.0f; } return result; } // ---------------------------------------------------------------------- void ShipController::dock(ShipObject & dockTarget, float const secondsAtDock) { LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::dock() owner(%s) dockTarget(%s) secondsAtDock(%.2f)", getOwner()->getNetworkId().getValueString().c_str(), dockTarget.getNetworkId().getValueString().c_str(), secondsAtDock)); // Create the docking behavior delete m_pendingDockingBehavior; m_pendingDockingBehavior = new AiShipBehaviorDock(*this, dockTarget, secondsAtDock); } // ---------------------------------------------------------------------- void ShipController::unDock() { if (m_pendingDockingBehavior != NULL) { m_pendingDockingBehavior->unDock(); } else if (m_dockingBehavior != NULL) { m_dockingBehavior->unDock(); } } // ---------------------------------------------------------------------- bool ShipController::isDocking() const { return (m_dockingBehavior != NULL) || (m_pendingDockingBehavior != NULL); } // ---------------------------------------------------------------------- bool ShipController::isDocked() const { return ((m_dockingBehavior != NULL) && m_dockingBehavior->isDocked()); } // ---------------------------------------------------------------------- void ShipController::onTargetedByMissile(int const /*missileId*/) { } //---------------------------------------------------------------------- ShipController * ShipController::asShipController() { return this; } //---------------------------------------------------------------------- ShipController const * ShipController::asShipController() const { return this; } // ---------------------------------------------------------------------- PlayerShipController * ShipController::asPlayerShipController() { return NULL; } // ---------------------------------------------------------------------- PlayerShipController const * ShipController::asPlayerShipController() const { return NULL; } // ---------------------------------------------------------------------- AiShipController * ShipController::asAiShipController() { return NULL; } // ---------------------------------------------------------------------- AiShipController const * ShipController::asAiShipController() const { return NULL; } // ---------------------------------------------------------------------- AiShipAttackTargetList const & ShipController::getAttackTargetList() const { return *m_attackTargetList; } // ---------------------------------------------------------------------- bool ShipController::addDamageTaken(NetworkId const & attackingUnit, float const damage, bool const verifyAttacker) { bool result = false; ShipObject * const attackingUnitShipObject = ShipObject::asShipObject(NetworkIdManager::getObjectById(attackingUnit)); if ( (attackingUnitShipObject != NULL) && !attackingUnitShipObject->isDamageAggroImmune()) { result = verifyAttacker ? Pvp::canAttack(*attackingUnitShipObject, *NON_NULL(getShipOwner())) : true; if (result) { m_attackTargetList->add(*attackingUnitShipObject, damage); } } return result; } // ---------------------------------------------------------------------- bool ShipController::hasTurretTargetingSystem() const { return (m_turretTargetingSystem != NULL); } // ---------------------------------------------------------------------- float ShipController::getTurretMissChance() const { return 0.5f; } // ---------------------------------------------------------------------- float ShipController::getTurretMissAngle() const { // Once player auto-turrets come online, this needs to be overloaded in PlayerShipController return tan(convertDegreesToRadians(10.0f)); } // ---------------------------------------------------------------------- void ShipController::clearEnemyCheckQueuedFlag() { m_enemyCheckQueued = false; } // ---------------------------------------------------------------------- bool ShipController::removeAttackTarget(NetworkId const & unit) { LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::removeAttackTarget() owner(%s) unit(%s)", getOwner()->getNetworkId().getValueString().c_str(), unit.getValueString().c_str())); return m_attackTargetList->remove(unit); } // ---------------------------------------------------------------------- void ShipController::onAttackTargetChanged(NetworkId const & target) { if (m_turretTargetingSystem != NULL) { m_turretTargetingSystem->onTargetChanged(target); } } // ---------------------------------------------------------------------- void ShipController::onAttackTargetLost(NetworkId const & target) { if (m_turretTargetingSystem != NULL) { m_turretTargetingSystem->onTargetLost(target); } } // ---------------------------------------------------------------------- void ShipController::onAttackTargetListEmpty() { // This is intentionally left blank } // ---------------------------------------------------------------------- float ShipController::getThrottle() const { return m_throttlePosition; } // ---------------------------------------------------------------------- int ShipController::getNumberOfAiUnitsAttackingMe() const { int result = 0; CachedNetworkIdList::const_iterator iterAiTargetingMeList = m_aiTargetingMeList->begin(); for (; iterAiTargetingMeList != m_aiTargetingMeList->end(); ++iterAiTargetingMeList) { CachedNetworkId const & ai = (*iterAiTargetingMeList); Object const * const aiObject = ai.getObject(); if (aiObject != NULL) { ShipController const * const shipController = aiObject->getController()->asShipController(); AiShipController const * const aiShipController = (shipController != NULL) ? shipController->asAiShipController() : NULL; if (aiShipController != NULL) { if (aiShipController->getPrimaryAttackTarget() == getOwner()->getNetworkId()) { ++result; } } } else { DEBUG_WARNING(true, ("ShipController::getNumberOfAiShipAttackingMe() ERROR: Why am I(%s) being targeted by a NULL object(%s)?", getOwner()->getDebugInformation().c_str(), ai.getValueString().c_str())); } } return result; } // ====================================================================== // PROTECTED ShipController // ====================================================================== ShipObject * ShipController::getShipOwner() { Object * const object = getOwner(); ServerObject * const serverObject = object ? object->asServerObject() : 0; return serverObject ? serverObject->asShipObject() : 0; } // ---------------------------------------------------------------------- ShipObject const * ShipController::getShipOwner() const { return const_cast(this)->getShipOwner(); } // ====================================================================== // PRIVATE ShipController // ====================================================================== void ShipController::synchronizeTransform() { } // ---------------------------------------------------------------------- void ShipController::experiencedCollision() { } // ---------------------------------------------------------------------- void ShipController::clearAiTargetingMeList() { // Notify all the ships targeting me that I am no longer valid s_purgeList.clear(); CachedNetworkIdList::const_iterator iterTargetByAiList = m_aiTargetingMeList->begin(); for (; iterTargetByAiList != m_aiTargetingMeList->end(); ++iterTargetByAiList) { CachedNetworkId const & id = *iterTargetByAiList; s_purgeList.push_back(id); } PurgeList::const_iterator iterPurgeList = s_purgeList.begin(); for (; iterPurgeList != s_purgeList.end(); ++iterPurgeList) { CachedNetworkId const & id = (*iterPurgeList); if (id.getObject() != NULL) { ShipController * const shipController = id.getObject()->getController()->asShipController(); if (shipController != NULL) { IGNORE_RETURN(shipController->removeAttackTarget(getOwner()->getNetworkId())); } else { LOGC(ConfigServerGame::isSpaceAiLoggingEnabled(), "space_debug_ai", ("ShipController::~ShipController() ERROR: owner(%s) targetedByUnit(%s) Why does this unit not have a ShipController?", getOwner()->getNetworkId().getValueString().c_str(), id.getValueString().c_str())); } } } } // ---------------------------------------------------------------------- void ShipController::getApproximateFutureTransform(Transform & transform, Vector & velocity, float elapsedTime) const { ServerShipObjectInterface const serverShipObjectInterface(getShipOwner()); m_shipDynamicsModel->getApproximateFutureTransform(transform, velocity, elapsedTime, serverShipObjectInterface); } // ======================================================================