/// <summary> /// Initializes a new instance of the <see cref="ShipOrder" /> class. /// </summary> /// <param name="directive">The order directive.</param> /// <param name="source">The source of this order.</param> /// <param name="toNotifyCmd">if set to <c>true</c> the ship will notify its Command of the outcome.</param> /// <param name="target">The target of this order. No need for FormationStation. Default is null.</param> public ShipOrder(ShipDirective directive, OrderSource source, bool toNotifyCmd = false, IShipNavigable target = null) { if (directive == ShipDirective.Move) { D.AssertEqual(typeof(ShipMoveOrder), GetType()); D.Assert(!toNotifyCmd); } if (directive.EqualsAnyOf(DirectivesWithNullTarget)) { D.AssertNull(target, ToString()); } Directive = directive; Source = source; ToNotifyCmd = toNotifyCmd; Target = target; }
private IMortalTarget GetTargetSelected(ShipDirective orderSelected, int subMenuItemId) { switch (orderSelected) { case ShipDirective.Join: return _joinableFleetLookup[subMenuItemId] as IMortalTarget; case ShipDirective.Disband: case ShipDirective.Refit: return _disbandRefitBaseLookup[subMenuItemId] as IMortalTarget; default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(orderSelected)); } }
private void __ValidateKnowledgeOfOrderTarget(IShipNavigable target, ShipDirective directive) { if (directive == ShipDirective.Retreat || directive == ShipDirective.Disband || directive == ShipDirective.Refit || directive == ShipDirective.StopAttack) { // directives aren't yet implemented return; } if (target is StarItem || target is SystemItem || target is UniverseCenterItem) { // unnecessary check as all players have knowledge of these targets return; } if (directive == ShipDirective.AssumeStation || directive == ShipDirective.Scuttle || directive == ShipDirective.Repair || directive == ShipDirective.Entrench || directive == ShipDirective.Disengage) { D.AssertNull(target); return; } if (directive == ShipDirective.Move) { if (target is StationaryLocation || target is MobileLocation) { return; } if (target is ISector) { return; // IMPROVE currently PlayerKnowledge does not keep track of Sectors } } if (!OwnerAIMgr.HasKnowledgeOf(target as IItem_Ltd)) { D.Error("{0} received {1} order with Target {2} that {3} has no knowledge of.", DebugName, directive.GetValueName(), target.DebugName, Owner.LeaderName); } }
void AssumingFormation_UponOrderOutcome(ShipDirective directive, ShipItem ship, bool isSuccess, IShipNavigable target, UnitItemOrderFailureCause failCause) { LogEvent(); if (directive != ShipDirective.AssumeStation) { D.Warn("{0} State {1} erroneously received OrderOutcome callback with {2} {3}.", DebugName, CurrentState.GetValueName(), typeof(ShipDirective).Name, directive.GetValueName()); return; } D.AssertNull(target); if (isSuccess) { _fsmShipWaitForOnStationCount--; } else { switch (failCause) { case UnitItemOrderFailureCause.UnitItemNeedsRepair: // Ship will get repaired, but even if it goes to its formationStation to do so // it won't communicate its success back to Cmd since Captain ordered it, not Cmd _fsmShipWaitForOnStationCount--; break; case UnitItemOrderFailureCause.UnitItemDeath: _fsmShipWaitForOnStationCount--; break; case UnitItemOrderFailureCause.TgtDeath: case UnitItemOrderFailureCause.TgtRelationship: case UnitItemOrderFailureCause.TgtUncatchable: case UnitItemOrderFailureCause.TgtUnreachable: case UnitItemOrderFailureCause.None: default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(failCause)); } } if (_fsmShipWaitForOnStationCount == Constants.Zero) { Return(); } }
protected virtual bool IsUserRemoteShipMenuItemDisabledFor(ShipDirective directive) { return false; }
private void UponOrderOutcome(ShipDirective directive, ShipItem ship, bool isSuccess, IShipNavigable target = null, UnitItemOrderFailureCause failCause = UnitItemOrderFailureCause.None) { RelayToCurrentState(directive, ship, isSuccess, target, failCause); }
/// <summary> /// Handles the results of the ship's attempt to execute the provided directive. /// </summary> /// <param name="directive">The directive.</param> /// <param name="ship">The ship.</param> /// <param name="isSuccess">if set to <c>true</c> the directive was successfully completed. May still be ongoing.</param> /// <param name="target">The target. Can be null.</param> /// <param name="failCause">The failure cause if not successful.</param> internal void HandleOrderOutcome(ShipDirective directive, ShipItem ship, bool isSuccess, IShipNavigable target = null, UnitItemOrderFailureCause failCause = UnitItemOrderFailureCause.None) { UponOrderOutcome(directive, ship, isSuccess, target, failCause); }
void ExecuteAttackOrder_UponOrderOutcome(ShipDirective directive, ShipItem ship, bool isSuccess, IShipNavigable target, UnitItemOrderFailureCause failCause) { LogEvent(); if (directive != ShipDirective.Attack) { D.Warn("{0} State {1} erroneously received OrderOutcome callback with {2} {3}.", DebugName, CurrentState.GetValueName(), typeof(ShipDirective).Name, directive.GetValueName()); return; } // TODO keep track of results to make better resulting decisions about what to do as battle rages // IShipAttackable attackedTgt = target as IShipAttackable; // target can be null if ship failed and didn't have a target: Disengaged... }
void ExecuteExploreOrder_UponOrderOutcome(ShipDirective directive, ShipItem ship, bool isSuccess, IShipNavigable target, UnitItemOrderFailureCause failCause) { LogEvent(); if (directive != ShipDirective.Explore) { D.Warn("{0} State {1} erroneously received OrderOutcome callback with {2} {3}.", DebugName, CurrentState.GetValueName(), typeof(ShipDirective).Name, directive.GetValueName()); return; } IShipExplorable shipExploreTgt = target as IShipExplorable; D.AssertNotNull(shipExploreTgt); bool issueFleetRecall = false; if (IsShipExploreTargetPartOfSystem(shipExploreTgt)) { // exploreTgt is a planet or star D.Assert(_shipSystemExploreTgtAssignments.ContainsKey(shipExploreTgt)); if (isSuccess) { HandleSystemTargetExploredOrDead(ship, shipExploreTgt); } else { bool isNewShipAssigned; bool testForAdditionalExploringShips = false; switch (failCause) { case UnitItemOrderFailureCause.TgtRelationship: // exploration failed so recall all ships issueFleetRecall = true; break; case UnitItemOrderFailureCause.TgtDeath: HandleSystemTargetExploredOrDead(ship, shipExploreTgt); // This is effectively counted as a success and will show up during the _EnterState's // continuous test System.IsFullyExplored. As not really a failure, no reason to issue a fleet recall. break; case UnitItemOrderFailureCause.UnitItemNeedsRepair: isNewShipAssigned = HandleShipNoLongerAvailableToExplore(ship, shipExploreTgt); if (!isNewShipAssigned) { if (Elements.Count > 1) { // This is not the last ship in the fleet, but the others aren't available. Since it usually takes // more than one ship to explore a System, the other ships might currently be exploring testForAdditionalExploringShips = true; } else { D.AssertEqual(Constants.One, Elements.Count); // Damaged ship is only one left in fleet and it can't explore so exploration failed issueFleetRecall = true; } } break; case UnitItemOrderFailureCause.UnitItemDeath: isNewShipAssigned = HandleShipNoLongerAvailableToExplore(ship, shipExploreTgt); if (!isNewShipAssigned) { if (Elements.Count > 1) { // >1 as dead ship has not yet been removed from fleet // This is not the last ship in the fleet, but the others aren't available. Since it usually takes // more than one ship to explore a System, the other ships might currently be exploring testForAdditionalExploringShips = true; } else { D.AssertEqual(Constants.One, Elements.Count); // dead ship has not yet been removed from fleet // Do nothing as Unit is about to die } } break; case UnitItemOrderFailureCause.TgtUncatchable: case UnitItemOrderFailureCause.TgtUnreachable: case UnitItemOrderFailureCause.None: default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(failCause)); } if (testForAdditionalExploringShips) { var otherShipsCurrentlyExploring = Elements.Cast<ShipItem>().Except(ship).Where(s => s.IsCurrentOrderDirectiveAnyOf(ShipDirective.Explore)); if (otherShipsCurrentlyExploring.Any()) { // Do nothing as there are other ships currently exploring so exploreTarget will eventually be assigned a ship } else { // There are no remaining ships out exploring -> the exploration attempt has failed so issue recall issueFleetRecall = true; } } } } else { // exploreTgt is UCenter D.Assert(shipExploreTgt is UniverseCenterItem); if (isSuccess) { // exploration of UCenter has successfully completed so issue fleet recall issueFleetRecall = true; } else { bool isNewShipAssigned; switch (failCause) { case UnitItemOrderFailureCause.UnitItemNeedsRepair: isNewShipAssigned = HandleShipNoLongerAvailableToExplore(ship, shipExploreTgt); if (!isNewShipAssigned) { // No more ships are available to finish UCenter explore. Since it only takes one ship // to explore UCenter, the other ships, if any, can't currently be exploring, so no reason to wait for them // to complete their exploration. -> the exploration attempt has failed so issue recall issueFleetRecall = true; } break; case UnitItemOrderFailureCause.UnitItemDeath: isNewShipAssigned = HandleShipNoLongerAvailableToExplore(ship, shipExploreTgt); if (!isNewShipAssigned) { if (Elements.Count > 1) { // >1 as dead ship has not yet been removed from fleet // This is not the last ship in the fleet, but the others aren't available. Since it only takes one ship // to explore UCenter, the other ships can't currently be exploring, so no reason to wait for them // to complete their exploration. -> the exploration attempt has failed so issue recall issueFleetRecall = true; } else { D.AssertEqual(Constants.One, Elements.Count); // dead ship has not yet been removed from fleet // Do nothing as Unit is about to die } } break; case UnitItemOrderFailureCause.TgtDeath: case UnitItemOrderFailureCause.TgtRelationship: case UnitItemOrderFailureCause.TgtUncatchable: case UnitItemOrderFailureCause.TgtUnreachable: case UnitItemOrderFailureCause.None: default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(failCause)); } } } if (issueFleetRecall) { IFleetExplorable fleetExploreTgt = CurrentOrder.Target as IFleetExplorable; var closestLocalAssyStation = GameUtility.GetClosest(Position, fleetExploreTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, closestLocalAssyStation); } }
/// <summary> /// The Captain uses this method to issue orders. /// </summary> /// <param name="order">The order.</param> /// <param name="retainSuperiorsOrder">if set to <c>true</c> [retain superiors order].</param> /// <param name="target">The target.</param> /// <param name="speed">The speed.</param> private void OverrideCurrentOrder(ShipDirective order, bool retainSuperiorsOrder, INavigableTarget target = null, Speed speed = Speed.None) { // if the captain says to, and the current existing order is from his superior, then record it as a standing order ShipOrder standingOrder = null; if (retainSuperiorsOrder && CurrentOrder != null) { if (CurrentOrder.Source != OrderSource.ElementCaptain) { // the current order is from the Captain's superior so retain it standingOrder = CurrentOrder; if (IsHQElement) { // the captain is overriding his superior on the flagship so declare an emergency // HACK Command.__OnHQElementEmergency(); } } else if (CurrentOrder.StandingOrder != null) { // the current order is from the Captain, but there is a standing order in it so retain it standingOrder = CurrentOrder.StandingOrder; } } ShipOrder newOrder = new ShipOrder(order, OrderSource.ElementCaptain, target, speed) { StandingOrder = standingOrder }; CurrentOrder = newOrder; }