void ExecuteJoinFleetOrder_EnterState() { LogEvent(); TryBreakOrbit(); var shipOrderSource = CurrentOrder.Source; // could be CmdStaff or User var fleetToJoin = CurrentOrder.Target as FleetCmdItem; string transferFleetName = "TransferTo_" + fleetToJoin.DebugName; FleetCmdItem transferFleetCmd; if (Command.Elements.Count > 1) { // detach from fleet and create the transferFleet Command.RemoveElement(this); transferFleetCmd = UnitFactory.Instance.MakeFleetInstance(transferFleetName, this); transferFleetCmd.CommenceOperations(); // 2 scenarios concerning PlayerKnowledge tracking these changes // - ship is HQ of current fleet // -> ship will lose isHQ and another will gain it. Handled by PK due to onIsHQChanged event // - ship is not HQ // -> no effect on PK when leaving // -> joining new fleet makes ship isHQ. Handled by PK due to onIsHQChanged event } else { // this ship's current fleet only has this ship so simply make it the transferFleet D.Assert(Command.Elements.Single().Equals(this)); transferFleetCmd = Command as FleetCmdItem; transferFleetCmd.Data.ParentName = transferFleetName; // no changes needed for PlayerKnowledge. Fleet name will be correct on next PK access } // issue a JoinFleet order to our transferFleet FleetOrder joinFleetOrder = new FleetOrder(FleetDirective.Join, shipOrderSource, fleetToJoin); transferFleetCmd.CurrentOrder = joinFleetOrder; // once joinFleetOrder takes, this ship state will be changed by its 'new' transferFleet Command }
void ExecuteGuardOrder_UponFsmTgtDeath(IMortalItem_Ltd deadFsmTgt) { LogEvent(); if (_fsmTgt != deadFsmTgt) { D.Error("{0}.target {1} is not dead target {2}.", DebugName, _fsmTgt.DebugName, deadFsmTgt.DebugName); } // TODO Communicate failure to boss? IGuardable guardableTgt = _fsmTgt as IGuardable; StationaryLocation assumeFormationTgt = GameUtility.GetClosest(Position, guardableTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, assumeFormationTgt); }
private void GetApMoveOrderSettings(FleetOrder moveOrder, out IFleetNavigable apMoveTgt, out Speed apMoveSpeed, out float apMoveTgtStandoffDistance) { D.Assert(moveOrder.Directive == FleetDirective.Move || moveOrder.Directive == FleetDirective.FullSpeedMove); // Determine move speed apMoveSpeed = moveOrder.Directive == FleetDirective.FullSpeedMove ? Speed.Full : Speed.Standard; // Determine move target IFleetNavigable moveTgt = null; IFleetNavigable moveOrderTgt = moveOrder.Target; ISystem_Ltd systemMoveTgt = moveOrderTgt as ISystem_Ltd; if (systemMoveTgt != null) { // move target is a system if (Topography == Topography.System) { // fleet is currently in a system ISector_Ltd fleetSector = SectorGrid.Instance.GetSectorContaining(Position); ISystem_Ltd fleetSystem = fleetSector.System; if (fleetSystem == systemMoveTgt) { // move target of a system from inside the same system is the closest assembly station within that system moveTgt = GameUtility.GetClosest(Position, systemMoveTgt.LocalAssemblyStations); } } } else { ISector_Ltd sectorMoveTgt = moveOrderTgt as ISector_Ltd; if (sectorMoveTgt != null) { // target is a sector ISector_Ltd fleetSector = SectorGrid.Instance.GetSectorContaining(Position); if (fleetSector == sectorMoveTgt) { // move target of a sector from inside the same sector is the closest assembly station within that sector moveTgt = GameUtility.GetClosest(Position, sectorMoveTgt.LocalAssemblyStations); } } } if (moveTgt == null) { moveTgt = moveOrderTgt; } apMoveTgt = moveTgt; // Determine move target standoff distance apMoveTgtStandoffDistance = CalcApMoveTgtStandoffDistance(moveOrderTgt); }
void ExecutePatrolOrder_UponFsmTgtInfoAccessChgd(IItem_Ltd fsmTgt) { LogEvent(); //D.Log(ShowDebugLog, "{0} received a FsmTgtInfoAccessChgd event while executing a patrol order.", DebugName); D.AssertEqual(_fsmTgt, fsmTgt as IFleetNavigable); IPatrollable patrollableTgt = _fsmTgt as IPatrollable; if (!patrollableTgt.IsPatrollingAllowedBy(Owner)) { D.Log(ShowDebugLog, "{0} {1} order for {2} is no longer valid as Relations with newly accessed Owner {3} is {4}.", DebugName, CurrentOrder.Directive.GetValueName(), patrollableTgt.DebugName, patrollableTgt.Owner_Debug, Owner.GetCurrentRelations(patrollableTgt.Owner_Debug).GetValueName()); // TODO Communicate failure to boss? StationaryLocation assumeFormationTgt = GameUtility.GetClosest(Position, patrollableTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, assumeFormationTgt); } }
void ExecuteGuardOrder_UponFsmTgtOwnerChgd(IItem_Ltd fsmTgt) { LogEvent(); D.AssertEqual(_fsmTgt, fsmTgt as IFleetNavigable); IGuardable guardableTgt = _fsmTgt as IGuardable; if (!guardableTgt.IsGuardingAllowedBy(Owner)) { D.Log(ShowDebugLog, "{0} {1} order for {2} is no longer valid as Relations with new Owner {3} is {4}.", DebugName, CurrentOrder.Directive.GetValueName(), guardableTgt.DebugName, guardableTgt.Owner_Debug, Owner.GetCurrentRelations(guardableTgt.Owner_Debug).GetValueName()); // TODO Communicate failure to boss? StationaryLocation assumeFormationTgt = GameUtility.GetClosest(Position, guardableTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, assumeFormationTgt); } }
void ExecuteExploreOrder_UponFsmTgtOwnerChgd(IItem_Ltd fsmTgt) { LogEvent(); D.AssertEqual(_fsmTgt, fsmTgt as IFleetNavigable); IFleetExplorable fleetExploreTgt = _fsmTgt as IFleetExplorable; if (!fleetExploreTgt.IsExploringAllowedBy(Owner) || fleetExploreTgt.IsFullyExploredBy(Owner)) { // new known owner is either at war with us or an ally Player fsmTgtOwner; bool isFsmTgtOwnerKnown = fleetExploreTgt.TryGetOwner(Owner, out fsmTgtOwner); D.Assert(isFsmTgtOwnerKnown); D.Log(ShowDebugLog, "{0} {1} order for {2} is no longer valid as Relations with new Owner {3} is {4}.", DebugName, CurrentOrder.Directive.GetValueName(), fleetExploreTgt.DebugName, fsmTgtOwner, Owner.GetCurrentRelations(fsmTgtOwner).GetValueName()); // TODO Communicate failure/success to boss? var closestLocalAssyStation = GameUtility.GetClosest(Position, fleetExploreTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, closestLocalAssyStation); } }
void ExecutePatrolOrder_UponRelationsChanged(Player chgdRelationsPlayer) { LogEvent(); IPatrollable patrollableTgt = _fsmTgt as IPatrollable; if (!patrollableTgt.IsPatrollingAllowedBy(Owner)) { D.Log(ShowDebugLog, "{0} {1} order for {2} is no longer valid as Relations with Owner {3} changed to {4}.", DebugName, CurrentOrder.Directive.GetValueName(), patrollableTgt.DebugName, patrollableTgt.Owner_Debug, Owner.GetCurrentRelations(patrollableTgt.Owner_Debug).GetValueName()); // TODO Communicate failure to boss? StationaryLocation assumeFormationTgt = GameUtility.GetClosest(Position, patrollableTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, assumeFormationTgt); } }
void ExecuteExploreOrder_UponRelationsChanged(Player chgdRelationsPlayer) { LogEvent(); IFleetExplorable fleetExploreTgt = _fsmTgt as IFleetExplorable; if (!fleetExploreTgt.IsExploringAllowedBy(Owner) || fleetExploreTgt.IsFullyExploredBy(Owner)) { // existing known owner either became an ally or they/we declared war Player fsmTgtOwner; bool isFsmTgtOwnerKnown = fleetExploreTgt.TryGetOwner(Owner, out fsmTgtOwner); D.Assert(isFsmTgtOwnerKnown); D.Log(ShowDebugLog, "{0} {1} order for {2} is no longer valid as Relations with Owner {3} changed to {4}.", DebugName, CurrentOrder.Directive.GetValueName(), fleetExploreTgt.DebugName, fsmTgtOwner, Owner.GetCurrentRelations(fsmTgtOwner).GetValueName()); // TODO Communicate failure/success to boss? var closestLocalAssyStation = GameUtility.GetClosest(Position, fleetExploreTgt.LocalAssemblyStations); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, closestLocalAssyStation); } }
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); } }
IEnumerator ExecuteExploreOrder_EnterState() { LogEvent(); IFleetExplorable fleetExploreTgt = _fsmTgt as IFleetExplorable; _apMoveSpeed = Speed.Standard; _apMoveTgtStandoffDistance = Constants.ZeroF; // can't explore a target owned by an enemy Call(FleetState.Moving); yield return null; // required so Return()s here if (_orderFailureCause != UnitItemOrderFailureCause.None) { switch (_orderFailureCause) { case UnitItemOrderFailureCause.UnitItemNeedsRepair: // TODO Initiate Fleet Repair and communicate failure to boss? break; case UnitItemOrderFailureCause.UnitItemDeath: // TODO Communicate failure to boss? break; case UnitItemOrderFailureCause.TgtRelationship: // TODO Communicate failure to boss? // No longer allowed to explore _fsmTgt, OR _fsmTgt is now fully explored IssueAssumeFormationOrderFromCmdStaff(); break; case UnitItemOrderFailureCause.TgtDeath: case UnitItemOrderFailureCause.TgtUncatchable: case UnitItemOrderFailureCause.TgtUnreachable: case UnitItemOrderFailureCause.None: default: throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(_orderFailureCause)); } yield return null; } // If there was a failure generated by Moving, resulting new Orders or Dead state should keep this point from being reached D.AssertDefault((int)_orderFailureCause, _orderFailureCause.GetValueName()); ISystem_Ltd systemExploreTgt = fleetExploreTgt as ISystem_Ltd; if (systemExploreTgt != null) { ExploreSystem(systemExploreTgt); } else { ISector_Ltd sectorExploreTgt = fleetExploreTgt as ISector_Ltd; if (sectorExploreTgt != null) { D.AssertNotNull(sectorExploreTgt.System); // Sector without a System is by definition fully explored so can't get here ExploreSystem(sectorExploreTgt.System); } else { IUniverseCenter_Ltd uCenterExploreTgt = fleetExploreTgt as IUniverseCenter_Ltd; D.AssertNotNull(uCenterExploreTgt); IList<ShipItem> exploreShips; bool hasShips = TryGetShips(out exploreShips, availableOnly: false, avoidHQ: true, qty: 1, priorityCats: _desiredExplorationShipCategories); D.Assert(hasShips); IShipExplorable uCenterShipExploreTgt = uCenterExploreTgt as IShipExplorable; D.AssertNotNull(uCenterShipExploreTgt); AssignShipToExploreItem(exploreShips[0], uCenterShipExploreTgt); // HACK } } while (!fleetExploreTgt.IsFullyExploredBy(Owner)) { // wait here until target is fully explored. If exploration fails, an AssumeFormation order will be issued ending this state yield return null; } StationaryLocation closestLocalAssyStation = GameUtility.GetClosest(Position, fleetExploreTgt.LocalAssemblyStations); D.LogBold(ShowDebugLog, "{0} has successfully completed exploration of {1}. Assuming Formation.", DebugName, fleetExploreTgt.DebugName); CurrentOrder = new FleetOrder(FleetDirective.AssumeFormation, OrderSource.CmdStaff, closestLocalAssyStation); }
/// <summary> /// Determines the AutoPilot move target from the provided moveOrder. /// Can be a StationaryLocation as the AutoPilot move target of a sector or a system /// from within the same system is the closest LocalAssemblyStation. /// </summary> /// <param name="moveOrder">The move order.</param> /// <returns></returns> private IFleetNavigable DetermineApMoveTarget(FleetOrder moveOrder) { D.Assert(moveOrder.Directive == FleetDirective.Move || moveOrder.Directive == FleetDirective.FullSpeedMove); // Determine move target IFleetNavigable apMoveTgt = null; IFleetNavigable moveOrderTgt = moveOrder.Target; ISystem_Ltd systemMoveTgt = moveOrderTgt as ISystem_Ltd; if (systemMoveTgt != null) { // move target is a system if (Topography == Topography.System) { // fleet is currently in a system ISector_Ltd fleetSector = SectorGrid.Instance.GetSectorContaining(Position); ISystem_Ltd fleetSystem = fleetSector.System; if (fleetSystem == systemMoveTgt) { // move target of a system from inside the same system is the closest assembly station within that system apMoveTgt = GameUtility.GetClosest(Position, systemMoveTgt.LocalAssemblyStations); } } } else { ISector_Ltd sectorMoveTgt = moveOrderTgt as ISector_Ltd; if (sectorMoveTgt != null) { // target is a sector ISector_Ltd fleetSector = SectorGrid.Instance.GetSectorContaining(Position); if (fleetSector == sectorMoveTgt) { // move target of a sector from inside the same sector is the closest assembly station within that sector apMoveTgt = GameUtility.GetClosest(Position, sectorMoveTgt.LocalAssemblyStations); } } } if (apMoveTgt == null) { apMoveTgt = moveOrderTgt; } return apMoveTgt; }
void ExecuteJoinFleetOrder_OnMakeFleetCompleted(FleetCmdModel transferFleet) { LogEvent(); var transferFleetView = transferFleet.Transform.GetSafeMonoBehaviour<FleetCmdView>(); transferFleetView.PlayerIntel.CurrentCoverage = IntelCoverage.Comprehensive; //TODO PlayerIntelCoverage should be set through sensor detection //CameraLosChangedListener enabled state handled by View.InitializeVisualMembers() // issue a JoinFleet order to our transferFleet var fleetToJoin = CurrentOrder.Target as ICmdTarget; FleetOrder joinFleetOrder = new FleetOrder(FleetDirective.Join, fleetToJoin); transferFleet.CurrentOrder = joinFleetOrder; //// once joinFleetOrder takes, this ship state will be changed by its 'new' transferFleet Command }