/// <summary> /// Handles the results of the facility's attempt to execute the provided directive. /// </summary> /// <param name="directive">The directive.</param> /// <param name="facility">The facility.</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(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target = null, UnitItemOrderFailureCause failCause = UnitItemOrderFailureCause.None) { UponOrderOutcome(directive, facility, isSuccess, target, failCause); }
private void UponOrderOutcome(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target, UnitItemOrderFailureCause failCause) { RelayToCurrentState(directive, facility, isSuccess, target, failCause); }
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 void ExecuteAttackOrder_UponOrderOutcome(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target, UnitItemOrderFailureCause failCause) { LogEvent(); if (directive != FacilityDirective.Attack) { D.Warn("{0} State {1} erroneously received OrderOutcome callback with {2} {3}.", DebugName, CurrentState.GetValueName(), typeof(FacilityDirective).Name, directive.GetValueName()); return; } // TODO What? It will be common for an attack by a facility to fail for cause unreachable as its target moves out of range... }
/// <summary> /// Evaluates whether the current Moving state should be reassessed by Return()ing /// it to the state that Call()ed it with an OrderFailureCause. /// <remarks>This method should only be called when the owner of _fsmTgt is known. /// There is no point in doing the evaluation if the owner is not known as it is /// ALWAYS OK to move to a target if the owner is unknown.</remarks> /// </summary> /// <param name="failCause">The resulting fail cause.</param> /// <param name="__isFsmInfoAccessChgd">if set to <c>true</c> [is FSM info access CHGD]. IMPROVE</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception> private bool ShouldMovingBeReassessed(out UnitItemOrderFailureCause failCause, bool __isFsmInfoAccessChgd) { bool toReassessMoving = false; UnitItemOrderFailureCause failureCause = UnitItemOrderFailureCause.None; switch (LastState) { case FleetState.ExecuteExploreOrder: IFleetExplorable fleetExploreTgt = _fsmTgt as IFleetExplorable; if (!fleetExploreTgt.IsExploringAllowedBy(Owner)) { // Owner exposure or relations change caused a loss of explore rights failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } if (fleetExploreTgt.IsFullyExploredBy(Owner)) { // last remaining ship explore target was explored by another fleet's ship owned by us // OR a relations change to Ally instantly made target fully explored failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } break; case FleetState.ExecutePatrolOrder: IPatrollable patrolTgt = _fsmTgt as IPatrollable; if (!patrolTgt.IsPatrollingAllowedBy(Owner)) { failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } break; case FleetState.ExecuteGuardOrder: IGuardable guardTgt = _fsmTgt as IGuardable; if (!guardTgt.IsGuardingAllowedBy(Owner)) { failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } break; case FleetState.ExecuteAttackOrder: IUnitAttackable unitAttackTgt = _fsmTgt as IUnitAttackable; if (__isFsmInfoAccessChgd) { if (!unitAttackTgt.IsAttackByAllowed(Owner)) { failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } } else { // If fsmOwner changed, then should not continue attack unless we are at War with new owner. // If fsmOwner relationship changed, then should not continue attack unless new relationship is War // Attack currently underway could have been on a ColdWar opponent. if (!unitAttackTgt.IsWarAttackByAllowed(Owner)) { failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } } break; case FleetState.ExecuteMoveOrder: var unitCmdMoveTgt = _fsmTgt as IUnitCmd_Ltd; if (unitCmdMoveTgt != null) { // as this is about standoff distance, only Units have weapons Player unitCmdMoveTgtOwner; bool haveOwnerAccess = unitCmdMoveTgt.TryGetOwner(Owner, out unitCmdMoveTgtOwner); if (!haveOwnerAccess) { D.Error("{0}.ShouldMovingBeReassessed() should not be called without Owner access.", DebugName); } // moving to fleet or base owned by player whose relations with us have changed, or whose ownership of _fsmTgt just became known if (Owner.IsEnemyOf(unitCmdMoveTgtOwner)) { // now known as an enemy if (!Owner.IsPreviouslyEnemyOf(unitCmdMoveTgtOwner)) { // definitely reassess as changed from non-enemy to enemy failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } // else no need to reassess as no change in being an enemy } else { // now known as not an enemy if (Owner.IsPreviouslyEnemyOf(unitCmdMoveTgtOwner)) { // changed from enemy to non-enemy so reassess as StandoffDistance can be shortened failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; } } } // Could also be moving to 1) an AssemblyStation from within a System or Sector, 2) a System or Sector // from outside, 3) a Planet, Star or UniverseCenter. Since none of these can fire on us, no reason to worry // about recalculating StandoffDistance. break; case FleetState.ExecuteJoinFleetOrder: // UNCLEAR an owner chg in our target Fleet (_fsmTgt) would show up here? IFleetCmd_Ltd tgtFleet = _fsmTgt as IFleetCmd_Ltd; if (tgtFleet.IsOwnerAccessibleTo(Owner)) { Player tgtFleetOwner; bool isAccessible = tgtFleet.TryGetOwner(Owner, out tgtFleetOwner); D.Assert(isAccessible); if (tgtFleetOwner == Owner) { // target fleet owner is still us break; } } // owner is no longer us failureCause = UnitItemOrderFailureCause.TgtRelationship; toReassessMoving = true; break; case FleetState.ExecuteAssumeFormationOrder: // shouldn't be possible case FleetState.Guarding: case FleetState.Patrolling: case FleetState.Moving: case FleetState.AssumingFormation: case FleetState.Idling: case FleetState.Dead: // doesn't Call() Moving case FleetState.Entrenching: case FleetState.GoRepair: case FleetState.Repairing: case FleetState.GoRefit: case FleetState.Refitting: case FleetState.GoRetreat: case FleetState.GoDisband: case FleetState.Disbanding: // not yet implemented case FleetState.None: default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(LastState)); } if (ShowDebugLog) { //string resultMsg = toReassessMoving ? "true, FailCause = {0}".Inject(failureCause.GetValueName()) : "false"; //D.Log("{0}.ShouldMovingBeReassessed() called. LastState = {1}, Result = {2}.", DebugName, LastState.GetValueName(), resultMsg); } failCause = failureCause; return toReassessMoving; }
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); } }