//-------------------------------------------------------------------------------------- // Determines/Calculates a path to the current movement target and sets it as the active path. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::DeterminePathToTarget(float deltaTime) { if(GetCurrentOrder()) { if(GetCurrentOrder()->GetOrderType() == MoveToPositionOrder && (GetCurrentOrder()->GetOrderPriority() == MediumPriority || GetCurrentOrder()->GetOrderPriority() == HighPriority) && !reinterpret_cast<MoveOrder*>(GetCurrentOrder())->GetPath()->empty()) { // Use the path provided by the team AI SetPath(reinterpret_cast<MoveOrder*>(GetCurrentOrder())->GetPath()); // If the path was started before, resume it. m_movementManager.SetCurrentNode(GetResumePathNode()); }else { // Let the soldier find a path himself. SetPath(m_movementManager.CreatePathTo(GetMovementTarget())); m_movementManager.SetCurrentNode(0); } // If there is no path to the target of the order, notify the team AI that the current order cannot be completed. if(!GetPath()) { UpdateOrderStateMessageData data(GetId(), FailedOrderState); SendMessage(GetTeamAI(), UpdateOrderStateMessageType, &data); } }else { // Let the soldier find a path himself. SetPath(m_movementManager.CreatePathTo(GetMovementTarget())); m_movementManager.SetCurrentNode(0); } return StatusSuccess; }
//-------------------------------------------------------------------------------------- // Moves the soldier entity towards a given target. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::MoveToTarget(float deltaTime) { if(m_movementManager.FollowPath(GetPath(), m_soldierProperties.m_targetReachedRadius, m_soldierProperties.m_maxSpeed)) { // The target was reached if(GetGreatestSuspectedThreat() && GetGreatestSuspectedThreat()->m_lastKnownPosition.x == GetMovementTarget().x && GetGreatestSuspectedThreat()->m_lastKnownPosition.y == GetMovementTarget().y) { int a = 4; } return StatusSuccess; } // Target not yet reached -> move the entity along the path avoiding obstacles and intersection with other soldiers // Note: Collision avoidance not really needed as pathfinding sufficient and avoidance of other entities not really // important at the moment. // m_movementManager.AvoidCollisions(m_soldierProperties.m_maxCollisionSeeAhead, m_soldierProperties.m_maxCollisionAvoidanceForce); m_movementManager.Separate(m_soldierProperties.m_separationRadius, m_soldierProperties.m_maxSeparationForce); m_movementManager.StayAwayFromWalls(m_soldierProperties.m_avoidWallsRadius, m_soldierProperties.m_maxAvoidWallsForce); m_movementManager.UpdatePosition(deltaTime, m_soldierProperties.m_maxSpeed, m_soldierProperties.m_maxTotalForce, m_soldierProperties.m_speedHandicap); if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == MoveToPositionOrder && GetCurrentOrder()->GetOrderPriority() != LowPriority) { // Remember the current path node in case the soldier gets interrupted by enemies. Soldier will be able to resume movement afterwards. // Does only work though if soldier doesn't move away (only fighting known threats) SetResumePathNode(m_movementManager.GetCurrentNode()); } return StatusRunning; }
//-------------------------------------------------------------------------------------- // Determines and sets the currently greatest known threat to the Soldier. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::DetermineGreatestKnownThreat(float deltaTime) { // Reset greatest known threat SetGreatestKnownThreat(nullptr); if(GetCurrentOrder()) { // Check if there is a current order that requires to attack a certain enemy. if(GetCurrentOrder()->GetOrderType() == AttackEnemyOrder && GetCurrentOrder()->GetOrderPriority() == HighPriority) { // If the target enemy is in a known threat of this soldier -> set him as greatest threat to make sure the soldier // attacks that target. unsigned long enemyId = reinterpret_cast<AttackOrder*>(GetCurrentOrder())->GetEnemyId(); if(IsKnownThreat(enemyId)) { SetGreatestKnownThreat(GetKnownThreat(enemyId)); }else { // The required enemy is not visible to the soldier but due to the high priority of the attack order, the // soldier is not allowed to attack other threats. Moving to the position of the require enemy is now his // main concern. Thus, no greatest known threat is set in order to bail out of the attack behaviour. // Add the requested enemy as a suspected threat if it is not in the list of suspected threats of the entity if(!IsSuspectedThreat(enemyId)) { AddSuspectedThreat(enemyId, reinterpret_cast<AttackOrder*>(GetCurrentOrder())->GetEnemyPosition(), false); }else { // Update the last known position of the suspected threat (entity's current value might be dated) GetSuspectedThreat(enemyId)->m_lastKnownPosition = reinterpret_cast<AttackOrder*>(GetCurrentOrder())->GetEnemyPosition(); } SetGreatestKnownThreat(nullptr); } return StatusSuccess; } if((GetCurrentOrder()->GetOrderType() == MoveToPositionOrder && GetCurrentOrder()->GetOrderPriority() == HighPriority) || ((GetCurrentOrder()->GetOrderType() == DefendPositionOrder && GetCurrentOrder()->GetOrderPriority() == HighPriority) && !IsAtTarget(reinterpret_cast<DefendOrder*>(GetCurrentOrder())->GetDefendPosition()))) { // The soldier has a high priority move order or has to move to a defend position asap. This means the soldier has // to ignore all enemies and try to reach his target. Thus, no greatest known threat is being set. SetGreatestKnownThreat(nullptr); return StatusSuccess; } } // No orders given that require special measures, just choose the greatest known threat as perceived by the soldier. SetGreatestKnownThreat(m_combatManager.DetermineGreatestKnownThreat()); return StatusSuccess; }
//-------------------------------------------------------------------------------------- // Finalise the movement of the entity when it reaches its objective. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::FinaliseMovement(float deltaTime) { SetResumePathNode(0); if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == MoveToPositionOrder) { UpdateOrderStateMessageData data(GetId(), SucceededOrderState); SendMessage(GetTeamAI(), UpdateOrderStateMessageType, &data); } return StatusSuccess; }
//-------------------------------------------------------------------------------------- // Tells whether the soldier is currently moving towards the greatest suspected threat in // order to investigate it or whether there now is a greater suspected threat that the // entity should tend to. It also factors in whether there are orders from the team AI based // on which the soldier should stop pursuing a target and tend to other objectives instead. // Returns true if the suspected threat being investigated is still the greatest suspected threat, // false otherwise and also if there is no suspected threat at all. //-------------------------------------------------------------------------------------- bool Soldier::IsInvestigatingGreatestSuspectedThreat(void) { if(GetCurrentOrder() && (GetCurrentOrder()->GetOrderType() == MoveToPositionOrder || GetCurrentOrder()->GetOrderType() == DefendPositionOrder) && (GetCurrentOrder()->GetOrderPriority() != LowPriority)) { // A higher level move or defend order has become active -> abort the pursuit of enemies and approach the target instead. return false; } // No specific orders, just check if there is a greater suspected threat (also valid for attack orders) return Entity::IsInvestigatingGreatestSuspectedThreat(); }
//-------------------------------------------------------------------------------------- // Determines a point to observe for the soldier and sets it as the active observation point. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::DetermineObservationTarget(float deltaTime) { // Reset observation target SetObservationTarget(XMFLOAT2(0.0f, 0.0f)); SetObservationTargetSet(false); if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == DefendPositionOrder) { // When being shot, react to it and attack the shooter while keeping the defend position for(std::vector<SuspectedThreat>::iterator it = GetSuspectedThreats().begin(); it != GetSuspectedThreats().end(); ++it) { if(it->m_hasHitEntity) { SetObservationTarget(it->m_lastKnownPosition); SetObservationTargetSet(true); return StatusSuccess; } } const XMFLOAT2& viewDirection = reinterpret_cast<DefendOrder*>(GetCurrentOrder())->GetViewDirection(); if(viewDirection.x != 0.0f || viewDirection.y != 0.0f) { // There is a defend order and a specific view direction that the entity should guard has been provided SetObservationTarget(XMFLOAT2(GetPosition().x + viewDirection.x, GetPosition().y + viewDirection.y)); SetObservationTargetSet(true); return StatusSuccess; } } // Otherwise determine a random look at target and change it in a fix interval // Update the timer m_changeObservationTargetTimer += deltaTime; // Check if the soldier should change his observation target if(m_changeObservationTargetTimer >= m_soldierProperties.m_lookAroundInterval) { // Determine a random lookAt position SetObservationTarget(XMFLOAT2(GetPosition().x + (rand() % 128 - 64), GetPosition().y + (rand() % 128 - 64))); SetObservationTargetSet(true); m_changeObservationTargetTimer = 0.0f; } return StatusSuccess; }
DWORD CFerianShipAI::OnCommunicate (CSpaceObject *pSender, MessageTypes iMessage, CSpaceObject *pParam1, DWORD dwParam2) // Communicate // // Handle communications from other objects { switch (iMessage) { case msgAttack: { if (GetCurrentOrder() == IShipController::orderMine && pSender == m_pBase) { SetState(stateAttackingThreat); m_pTarget = pParam1; return resAck; } else return resNoAnswer; } default: return resNoAnswer; } }
//-------------------------------------------------------------------------------------- // Removes the currently active suspected threat from the list of suspected threats. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::ResolveSuspectedThreat(float deltaTime) { if(GetGreatestSuspectedThreat()) { RemoveSuspectedThreat(GetGreatestSuspectedThreat()->m_enemyId); // If the soldier was investigating the suspected threat in order to find and attack an enemy that // was the target of an attack order, notify the team AI that the attack failed if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == AttackEnemyOrder && reinterpret_cast<AttackOrder*>(GetCurrentOrder())->GetEnemyId() == GetGreatestSuspectedThreat()->m_enemyId) { // Notify team AI that attack order failed UpdateOrderStateMessageData data(GetId(), FailedOrderState); SendMessage(GetTeamAI(), UpdateOrderStateMessageType, &data); } } return StatusSuccess; }
//-------------------------------------------------------------------------------------- // Determines and sets the currently greatest suspected threat to the Soldier. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::DetermineGreatestSuspectedThreat(float deltaTime) { if(GetCurrentOrder()) { if(GetCurrentOrder()->GetOrderPriority() == HighPriority || GetCurrentOrder()->GetOrderPriority() == MediumPriority) { if(GetCurrentOrder()->GetOrderPriority() == HighPriority && GetCurrentOrder()->GetOrderType() == AttackEnemyOrder) { // Only move to the requested enemy SetGreatestSuspectedThreat(GetSuspectedThreat(reinterpret_cast<AttackOrder*>(GetCurrentOrder())->GetEnemyId())); return StatusSuccess; } // For any other orders of priority high and medium, soliders should not investigate any suspected threats (that also // means not pursue any enemies) as there are other objectives of higher priority. SetGreatestSuspectedThreat(nullptr); return StatusSuccess; } } // No orders given that require special measures, just choose the greatest suspected threat as perceived by the soldier. SetGreatestSuspectedThreat(m_combatManager.DetermineGreatestSuspectedThreat()); return StatusSuccess; }
CSpaceObject *CZoanthropeAI::GetBase (void) const // GetBase // // Returns this ship's base { switch (GetCurrentOrder()) { case IShipController::orderGuard: case IShipController::orderPatrol: return GetCurrentOrderTarget(); default: return NULL; } }
CString CAutonAI::DebugCrashInfo (void) // DebugCrashInfo // // Returns debug crash info { CString sResult; sResult.Append(CONSTLIT("CAutonAI\r\n")); sResult.Append(strPatternSubst(CONSTLIT("Order: %d\r\n"), (int)GetCurrentOrder())); sResult.Append(strPatternSubst(CONSTLIT("m_State: %d\r\n"), m_State)); sResult.Append(strPatternSubst(CONSTLIT("m_pDest: %s\r\n"), CSpaceObject::DebugDescribe(m_pDest))); sResult.Append(strPatternSubst(CONSTLIT("m_pTarget: %s\r\n"), CSpaceObject::DebugDescribe(m_pTarget))); return sResult; }
void CFerianShipAI::OnObjDestroyedNotify (const SDestroyCtx &Ctx) // OnObjDestroyedNotify // // Deal with an object that has been destroyed { switch (GetCurrentOrder()) { case IShipController::orderMine: { if (Ctx.pObj == GetCurrentOrderTarget()) { // Avenge the base if (Ctx.pDestroyer && Ctx.pDestroyer->CanAttack() && !m_pShip->IsFriend(Ctx.pDestroyer)) AddOrder(IShipController::orderDestroyTarget, Ctx.pDestroyer, 0); else if (m_State == stateAttackingThreat) AddOrder(IShipController::orderDestroyTarget, m_pTarget, 0); // Stop mining CancelCurrentOrder(); } break; } default: break; } // Reset if (m_pBase == Ctx.pObj) { SetState(stateNone); m_pBase = NULL; } if (m_pTarget == Ctx.pObj) { SetState(stateNone); m_pTarget = NULL; } }
void CShips::ExtractDeuterium(CShipMap& ships) { AssertBotE(GetCurrentOrder() == SHIP_ORDER::EXTRACT_DEUTERIUM); for(CShips::iterator i = begin(); i != end();) { i->second->ExtractDeuterium(ships); if(!i->second->CanExtractDeuterium()) { ships.Add(i->second); i->second->UnsetCurrentOrder(); RemoveShipFromFleet(i); continue; } ++i; } CShip::ExtractDeuterium(); if(!CShip::CanExtractDeuterium()) { CShip::UnsetCurrentOrder(); if(HasFleet()) ships.Add(GiveFleetToFleetsFirstShip()); } }
void CShips::RepairCommand(BOOL bAtShipPort, bool bFasterShieldRecharge, CShipMap& ships) { AssertBotE(GetCurrentOrder() == SHIP_ORDER::REPAIR); if(!bAtShipPort) { UnsetCurrentOrder(); return; } for(CShips::iterator i = begin(); i != end();) { i->second->RepairCommand(bAtShipPort, bFasterShieldRecharge, ships); if(!i->second->NeedsRepair()) { ships.Add(i->second); RemoveShipFromFleet(i); continue; } ++i; } CShip::Repair(bAtShipPort, bFasterShieldRecharge); if(!CShip::NeedsRepair()) { CShip::UnsetCurrentOrder(); if(HasFleet()) ships.Add(GiveFleetToFleetsFirstShip()); } }
CString CZoanthropeAI::DebugCrashInfo (void) // DebugCrashInfo // // Returns debug crash info { CString sOrder; try { sOrder = strFromInt((int)GetCurrentOrder()); } catch (...) { } // If GetCurrentOrder crashes, try to determine why if (sOrder.IsBlank()) { try { sOrder = strPatternSubst(CONSTLIT("crash in GetCurrentOrder; count = %d\r\n"), m_Orders.GetCount()); } catch (...) { sOrder = CONSTLIT("crash in GetCurrentOrder\r\n"); } } CString sResult = CONSTLIT("CZoanthropeAI\r\n"); sResult.Append(strPatternSubst(CONSTLIT("Order: %s\r\n"), sOrder)); sResult.Append(strPatternSubst(CONSTLIT("m_State: %d\r\n"), m_State)); sResult.Append(strPatternSubst(CONSTLIT("m_pBase: %s\r\n"), CSpaceObject::DebugDescribe(m_pBase))); sResult.Append(strPatternSubst(CONSTLIT("m_pTarget: %s\r\n"), CSpaceObject::DebugDescribe(m_pTarget))); return sResult; }
void CShips::AddShipToFleet(const boost::shared_ptr<CShips>& fleet) { CString s; if(MT::CMyTrace::IsLoggingEnabledFor("ships")) { s.Format("CShips: adding ship with leader %s to fleet of %s", fleet->m_sName, m_sName); MYTRACE("ships")(MT::LEVEL_INFO, s); } AssertBotE(fleet->OwnerID() == OwnerID()); const CShipMap::iterator i = m_Fleet.Add(fleet); const SHIP_ORDER::Typ order = GetCurrentOrder(); AssertBotE(order != SHIP_ORDER::ASSIGN_FLAGSHIP); if(!i->second->CanHaveOrder(order, false)) UnsetCurrentOrder(); i->second->AdoptOrdersFrom(*this); if(fleet->HasFleet()) { if(MT::CMyTrace::IsLoggingEnabledFor("ships")) { s.Format("CShips: adding the fleet of leader %s to fleet of %s", fleet->m_sName, m_sName); MYTRACE("ships")(MT::LEVEL_INFO, s); } m_Fleet.Append(i->second->m_Fleet); i->second->Reset(); } }
//-------------------------------------------------------------------------------------- // Determines and sets a patrol target position for the soldier. // Param1: The time in seconds passed since the last frame. // Returns the current state of the action. //-------------------------------------------------------------------------------------- BehaviourStatus Soldier::DetermineMovementTarget(float deltaTime) { // Reset movement target SetMovementTarget(XMFLOAT2(0.0f, 0.0f)); SetMovementTargetSet(false); if(GetCurrentOrder()) { if(GetCurrentOrder()->GetOrderType() == DefendPositionOrder) { if(IsAtTarget(reinterpret_cast<DefendOrder*>(GetCurrentOrder())->GetDefendPosition())) { SetMovementTargetSet(false); }else { SetMovementTarget(reinterpret_cast<DefendOrder*>(GetCurrentOrder())->GetDefendPosition()); SetMovementTargetSet(true); } }else if(GetCurrentOrder()->GetOrderType() == MoveToPositionOrder) { SetMovementTarget(reinterpret_cast<MoveOrder*>(GetCurrentOrder())->GetTargetPosition()); SetMovementTargetSet(true); } }else { // If there is no order, just pick a random target position within the test environment to patrol XMFLOAT2 patrolTarget(0.0f, 0.0f); if(GetTestEnvironment()->GetRandomUnblockedTarget(patrolTarget)) { m_movementManager.Reset(); SetMovementTarget(patrolTarget); SetMovementTargetSet(true); }else { SetMovementTargetSet(false); } } // Always succeeds return StatusSuccess; }
//-------------------------------------------------------------------------------------- // Tells whether the entity is currently moving towards the highest priority movement target // or whether there now is a higher priority target that the entity should move towards instead. // Returns true if the target being moved towards is still the highest priority target, // false otherwise and also if there is no movement target set at all. //-------------------------------------------------------------------------------------- bool Soldier::IsMovingToHighestPriorityTarget(void) { if(!IsMovementTargetSet()) { return false; } if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == MoveToPositionOrder) { // A movement order was received, which has higher priority than normal movement. Check if // the entity is moving towards the ordered movement target. const XMFLOAT2& orderTarget = reinterpret_cast<MoveOrder*>(GetCurrentOrder())->GetTargetPosition(); if(GetMovementTarget().x != orderTarget.x || GetMovementTarget().y != orderTarget.y) { // Soldier should stop moving to current target and follow order instead // Soldier won't be able to resume the path later on SetResumePathNode(0); return false; } }else if(GetCurrentOrder() && GetCurrentOrder()->GetOrderType() == DefendPositionOrder) { // A defned order was received, which has higher priority than normal movement. Check if // the entity is moving towards the defend target. const XMFLOAT2& orderTarget = reinterpret_cast<DefendOrder*>(GetCurrentOrder())->GetDefendPosition(); if(GetMovementTarget().x != orderTarget.x || GetMovementTarget().y != orderTarget.y) { // Soldier should stop moving to current target and follow order instead // Soldier won't be able to resume the path later on SetResumePathNode(0); return false; } } return true; }
void CZoanthropeAI::BehaviorStart (void) // BehaviorStart // // Figure out what to do based on orders { switch (GetCurrentOrder()) { case IShipController::orderNone: { if (m_pShip->GetDockedObj() == NULL) AddOrder(IShipController::orderGate, NULL, IShipController::SData()); break; } case IShipController::orderEscort: { CSpaceObject *pPrincipal = GetCurrentOrderTarget(); ASSERT(pPrincipal); SetState(stateOnEscortCourse, pPrincipal); m_pShip->Communicate(m_pBase, msgEscortReportingIn, m_pShip); break; } case IShipController::orderFollowPlayerThroughGate: SetState(stateOnCourseForStargate, m_pShip->GetNearestStargate()); break; case IShipController::orderGate: { // Look for the gate CSpaceObject *pGate = GetCurrentOrderTarget(); if (pGate == NULL) pGate = m_pShip->GetNearestStargate(true); // Head for the gate if (pGate) SetState(stateOnCourseForStargate, pGate); break; } case IShipController::orderGuard: { CSpaceObject *pPrincipal = GetCurrentOrderTarget(); ASSERT(pPrincipal); // If we're not docked, dock with principal if (m_pShip->GetDockedObj() == NULL) SetState(stateReturningFromThreat, pPrincipal); // Otherwise, wait for a threat else SetState(stateWaitingForThreat, pPrincipal); break; } case IShipController::orderPatrol: { CSpaceObject *pPrincipal = GetCurrentOrderTarget(); ASSERT(pPrincipal); SetState(stateOnPatrolOrbit, pPrincipal); break; } case IShipController::orderWaitForPlayer: { SetState(stateWaiting); break; } } }
void CAutonAI::BehaviorStart (void) // BehaviorStart // // Initiate behavior state based on orders { switch (GetCurrentOrder()) { case IShipController::orderNone: { if (m_pShip->GetDockedObj() == NULL) AddOrder(IShipController::orderGate, NULL, IShipController::SData()); break; } case IShipController::orderEscort: { // If this is a support ship, then we follow. Otherwise we // are an armed escort. if (m_AICtx.IsNonCombatant()) SetState(stateFollowing); else SetState(stateEscorting); m_pDest = GetCurrentOrderTarget(); ASSERT(m_pDest); m_pShip->Communicate(m_pDest, msgEscortReportingIn, m_pShip); break; } case IShipController::orderFollowPlayerThroughGate: { SetState(stateOnCourseForStargate); m_pDest = m_pShip->GetNearestStargate(); break; } case IShipController::orderGate: { // Look for the gate CSpaceObject *pGate = GetCurrentOrderTarget(); if (pGate == NULL) pGate = m_pShip->GetNearestStargate(true); // Head for the gate if (pGate) { SetState(stateOnCourseForStargate); m_pDest = pGate; } break; } case IShipController::orderWaitForPlayer: { SetState(stateWaiting); break; } } }
DWORD CAutonAI::OnCommunicate (CSpaceObject *pSender, MessageTypes iMessage, CSpaceObject *pParam1, DWORD dwParam2) // Communicate // // Handle communications from other objects { switch (iMessage) { case msgAttack: case msgAttackDeter: { if (GetCurrentOrder() == IShipController::orderEscort && !m_AICtx.IsNonCombatant()) { SetState(stateAttackingTarget); m_pTarget = pParam1; return resAck; } else return resNoAnswer; } case msgAbort: { SetState(stateNone); return resAck; } case msgFormUp: { if (m_State == stateWaiting || m_State == stateAttackingTarget) { SetState(stateNone); return resAck; } else return resNoAnswer; } case msgQueryCommunications: { if (GetCurrentOrder() == IShipController::orderEscort) { DWORD dwRes = 0; if (!m_AICtx.IsNonCombatant()) dwRes |= resCanAttack; if (m_State == stateAttackingTarget) dwRes |= (resCanAbortAttack | resCanFormUp); if (m_State != stateWaiting) dwRes |= resCanWait; else dwRes |= resCanFormUp; return dwRes; } else return 0; } case msgQueryEscortStatus: { if (GetEscortPrincipal() == pParam1) return resAck; else return resNoAnswer; } case msgQueryWaitStatus: return (m_State == stateWaiting ? resAck : resNoAnswer); case msgWait: { if (GetCurrentOrder() == IShipController::orderEscort) { SetState(stateWaiting); m_pDest = GetCurrentOrderTarget(); return resAck; } else return resNoAnswer; } default: return resNoAnswer; } }
void CFerianShipAI::BehaviorStart (void) // BehaviorStart // // Figure out what to do based on orders { switch (GetCurrentOrder()) { case IShipController::orderNone: { if (m_pShip->GetDockedObj() == NULL) AddOrder(IShipController::orderGate, NULL, 0); break; } case IShipController::orderDestroyTarget: { SetState(stateAttackingTarget); m_pTarget = GetCurrentOrderTarget(); ASSERT(m_pTarget); ASSERT(m_pTarget->DebugIsValid() && m_pTarget->NotifyOthersWhenDestroyed()); break; } case IShipController::orderMine: { m_pBase = GetCurrentOrderTarget(); ASSERT(m_pBase); SetState(stateOnCourseForMine); m_pTarget = FindRandomAsteroid(); if (m_pTarget == NULL) { SetState(stateOnCourseForStargate); m_pBase = m_pShip->GetNearestStargate(true); } break; } case IShipController::orderGate: { // Look for the gate CSpaceObject *pGate = GetCurrentOrderTarget(); if (pGate == NULL) pGate = m_pShip->GetNearestStargate(true); // Head for the gate if (pGate) { SetState(stateOnCourseForStargate); m_pBase = pGate; } break; } case IShipController::orderDestroyPlayerOnReturn: { CSpaceObject *pGate = m_pShip->GetNearestStargate(); if (pGate) { SetState(stateWaitForPlayerAtGate); m_pBase = pGate; } break; } default: break; } }
void CFleetShipAI::OnObjDestroyedNotify (const SDestroyCtx &Ctx) // OnObjDestroyedNotify // // Deal with an object that has been destroyed { switch (GetCurrentOrder()) { case IShipController::orderEscort: if (Ctx.pObj == GetCurrentOrderTarget()) { CancelCurrentOrder(); // Get the orders of the leader IShipController::OrderTypes iLeaderOrders = IShipController::orderNone; CSpaceObject *pLeaderTarget = NULL; if (Ctx.pObj && Ctx.pObj->GetCategory() == CSpaceObject::catShip) { CShip *pLeader = Ctx.pObj->AsShip(); if (pLeader) iLeaderOrders = pLeader->GetController()->GetCurrentOrderEx(&pLeaderTarget); } // Avenge the leader int iAvengeChance = (pLeaderTarget ? 40 : 100); if (Ctx.pDestroyer && Ctx.pDestroyer != pLeaderTarget && Ctx.pDestroyer->CanAttack() && !m_pShip->IsFriend(Ctx.pDestroyer) && mathRandom(1, 100) <= iAvengeChance) AddOrder(IShipController::orderDestroyTarget, Ctx.pDestroyer, 0); // Take on leader's orders switch (iLeaderOrders) { case IShipController::orderDestroyTarget: case IShipController::orderGuard: if (pLeaderTarget) AddOrder(iLeaderOrders, pLeaderTarget, 0); break; default: break; } // Attack other enemies AddOrder(IShipController::orderAttackNearestEnemy, NULL, 0); } break; case IShipController::orderDock: case IShipController::orderDestroyTarget: case IShipController::orderPatrol: case IShipController::orderGuard: if (Ctx.pObj == GetCurrentOrderTarget()) CancelCurrentOrder(); break; default: break; } // If our target gets destroyed... switch (m_State) { case stateAttackTarget: case stateAttackOnPatrol: if (Ctx.pObj == m_pTarget) SetState(stateNone); break; default: break; } // Reset if (m_pDest == Ctx.pObj) m_pDest = NULL; if (m_pTarget == Ctx.pObj) m_pTarget = NULL; }
DWORD CFleetShipAI::OnCommunicate (CSpaceObject *pSender, MessageTypes iMessage, CSpaceObject *pParam1, DWORD dwParam2) // Communicate // // Handle communications from other objects { switch (iMessage) { case msgAbort: { if (m_State == stateAttackTarget || m_State == stateAttackAtWill || m_State == stateAttackInFormation) SetState(stateNone); return resAck; } case msgAttack: { if (GetCurrentOrder() == IShipController::orderEscort) { SetState(stateAttackTarget); m_pTarget = pParam1; m_iCounter = 0; ASSERT(m_pTarget); return resAck; } else return resNoAnswer; } case msgAttackInFormation: { if (GetCurrentOrder() == IShipController::orderEscort) { SetState(stateAttackInFormation); m_iCounter = dwParam2; return resAck; } else return resNoAnswer; } case msgBreakAndAttack: { if (GetCurrentOrder() == IShipController::orderEscort) { SetState(stateAttackAtWill); return resAck; } else return resNoAnswer; } case msgFormUp: { if (GetCurrentOrder() == IShipController::orderEscort) { if (dwParam2 != 0xffffffff) SetCurrentOrderData(dwParam2); SetState(stateNone); return resAck; } else return resNoAnswer; } case msgQueryCommunications: { if (GetCurrentOrder() == IShipController::orderEscort && GetCurrentOrderTarget() == pSender) { DWORD dwRes = (resCanBeInFormation | resCanAttack | resCanBreakAndAttack); if (m_State == stateAttackTarget || m_State == stateAttackAtWill || m_State == stateAttackInFormation) dwRes |= resCanAbortAttack; else if (m_State == stateKeepFormation) dwRes |= resCanAttackInFormation; return dwRes; } else return resNoAnswer; } case msgQueryEscortStatus: case msgQueryFleetStatus: { if (GetEscortPrincipal() == pParam1) return resAck; else return resNoAnswer; } default: return resNoAnswer; } }
void CFleetShipAI::BehaviorStart (void) // BehaviorStart // // Figure out what to do based on orders { switch (GetCurrentOrder()) { case IShipController::orderNone: { if (m_pShip->GetDockedObj() == NULL) AddOrder(IShipController::orderGate, NULL, 0); break; } case IShipController::orderAttackNearestEnemy: { CSpaceObject *pTarget = m_pShip->GetNearestEnemy(ATTACK_AT_WILL_RANGE, true); if (pTarget) { SetState(stateAttackTarget); m_pTarget = pTarget; m_iCounter = 0; } else CancelCurrentOrder(); break; } case IShipController::orderDestroyTarget: { SetState(stateAttackTarget); m_pTarget = GetCurrentOrderTarget(); m_iCounter = 0; ASSERT(m_pTarget); break; } case IShipController::orderDock: { CSpaceObject *pDest = GetCurrentOrderTarget(); ASSERT(pDest); // If we're docked with our destination then we're done. if (m_pShip->GetDockedObj() == pDest) CancelCurrentOrder(); // Otherwise, try to dock else { SetState(stateOnCourseForDocking); m_pDest = pDest; } break; } case IShipController::orderEscort: { SetState(stateKeepFormation); m_pLeader = GetCurrentOrderTarget(); ASSERT(m_pLeader); m_iFormation = (int)HIWORD(GetCurrentOrderData()); m_iPlace = (int)LOWORD(GetCurrentOrderData()); ASSERT(m_iFormation < FORMATIONS_COUNT); // If there is no place for this ship in the formation, then // gate-out if (m_iFormation >= FORMATIONS_COUNT || m_iPlace >= g_Formations[m_iFormation].iCount) { CancelCurrentOrder(); break; } // Keep formation m_pShip->Communicate(m_pLeader, msgEscortReportingIn, m_pShip); break; } case IShipController::orderFollowPlayerThroughGate: { SetState(stateOnCourseForStargate); m_pDest = m_pShip->GetNearestStargate(); break; } case IShipController::orderGate: { // Look for the gate CSpaceObject *pGate = GetCurrentOrderTarget(); if (pGate == NULL) pGate = m_pShip->GetNearestStargate(true); // Head for the gate if (pGate) { SetState(stateOnCourseForStargate); m_pDest = pGate; } break; } case IShipController::orderPatrol: case IShipController::orderGuard: { SetState(stateOnPatrolOrbit); m_pDest = GetCurrentOrderTarget(); ASSERT(m_pDest); break; } default: break; } }