protected override void Add(IMortalTarget target) { base.Add(target); D.Assert(Owner != null); if (Owner.IsEnemyOf(target.Owner) && !target.IsAlive && !EnemyTargets.Contains(target)) { AddEnemyTarget(target); } }
private void AddEnemyTarget(IMortalTarget enemyTarget) { D.Log("{0}.{1}({2:0.00}) added Enemy {3} at distance {4}.", ParentFullName, _transform.name, Range, enemyTarget.FullName, Vector3.Distance(_transform.position, enemyTarget.Position)); if (EnemyTargets.Count == 0) { OnEnemyInRange(true); // there are now enemies in range } EnemyTargets.Add(enemyTarget); }
/// <summary> /// Plots a course to a Planetoid target and notifies the requester of the /// outcome via the onCoursePlotSuccess or Failure events. /// </summary> /// <param name="planetoid">The planetoid.</param> /// <param name="speed">The speed.</param> /// <param name="standoffDistance">The distance to standoff from the target. This is added to the radius of the target to /// determine how close the ship is allowed to approach the target.</param> /// <param name="isFleetMove">>if set to <c>true</c> this navigator will only move when the fleet is ready.</param> private void PlotCourse(IMortalTarget planetoid, Speed speed, float standoffDistance, bool isFleetMove) { // a formationOffset is required if this is a fleet move Vector3 destinationOffset = isFleetMove ? _data.FormationStation.StationOffset : Vector3.zero; _targetInfo = new TargetInfo(planetoid, destinationOffset, standoffDistance); Speed = speed; _isFleetMove = isFleetMove; InitializeTargetValues(); //PlotCourse(); }
/// <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> private void OverrideCurrentOrder(FacilityDirective order, bool retainSuperiorsOrder, IMortalTarget target = null) { // if the captain says to, and the current existing order is from his superior, then record it as a standing order FacilityOrder 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; } 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; } } FacilityOrder newOrder = new FacilityOrder(order, OrderSource.ElementCaptain, target) { StandingOrder = standingOrder }; CurrentOrder = newOrder; }
void ExecuteAttackOrder_ExitState() { LogEvent(); _ordersTarget = null; _primaryTarget = null; _isDestinationUnreachable = false; }
protected override void Remove(IMortalTarget target) { base.Remove(target); RemoveEnemyTarget(target); }
void Attacking_ExitState() { LogEvent(); _attackTarget.onTargetDeathOneShot -= OnTargetDeath; _attackTarget = null; }
void Attacking_EnterState() { LogEvent(); _attackTarget = CurrentOrder.Target as IMortalTarget; _attackTarget.onTargetDeathOneShot += OnTargetDeath; var elementAttackOrder = new FacilityOrder(FacilityDirective.Attack, OrderSource.UnitCommand, _attackTarget); Elements.ForAll(e => (e as FacilityModel).CurrentOrder = elementAttackOrder); }
void Attacking_EnterState() { LogEvent(); _attackTarget = CurrentOrder.Target as IMortalTarget; _attackTarget.onTargetDeathOneShot += OnTargetDeath; var shipAttackOrder = new ShipOrder(ShipDirective.Attack, OrderSource.UnitCommand, _attackTarget); Elements.ForAll(e => (e as ShipModel).CurrentOrder = shipAttackOrder); }
public TargetInfo(IMortalTarget planetoid, Vector3 fstOffset, float standoffDistance) { Target = planetoid; Destination = planetoid.Position + fstOffset; CloseEnoughDistance = planetoid.Radius + standoffDistance; CloseEnoughDistanceSqrd = CloseEnoughDistance * CloseEnoughDistance; }
protected virtual void Remove(IMortalTarget target) { bool isRemoved = AllTargets.Remove(target); if (isRemoved) { //D.Log("{0}.{1} no longer tracking target {2} at distance = {3}.", ParentFullName, _transform.name, target.FullName, Vector3.Distance(target.Position, _transform.position)); target.onTargetDeathOneShot -= OnTargetDeath; target.onOwnerChanged -= OnTargetOwnerChanged; } else { D.Warn("{0}.{1} target {2} not present to be removed.", ParentFullName, _transform.name, target.FullName); } }
protected virtual void Add(IMortalTarget target) { if (!AllTargets.Contains(target)) { if (!target.IsAlive) { //D.Log("{0}.{1} now tracking target {2}.", ParentFullName, _transform.name, target.FullName); target.onTargetDeathOneShot += OnTargetDeath; target.onOwnerChanged += OnTargetOwnerChanged; AllTargets.Add(target); } else { D.Log("{0}.{1} avoided adding target {2} that is already dead but not yet destroyed.", ParentFullName, _transform.name, target.FullName); } } else { D.Warn("{0}.{1} attempted to add duplicate Target {2}.", ParentFullName, _transform.name, target.FullName); } }
void OnTargetDeath(IMortalTarget deadTarget) { RelayToCurrentState(deadTarget); }
/// <summary> /// Picks the highest priority target from orders. First selection criteria is inRange. /// </summary> /// <param name="chosenTarget">The chosen target from orders or null if no targets remain alive.</param> /// <returns> <c>true</c> if the target is in range, <c>false</c> otherwise.</returns> private bool PickPrimaryTarget(out IMortalTarget chosenTarget) { D.Assert(_ordersTarget != null && _ordersTarget.IsAlive, "{0}'s target from orders is null or dead.".Inject(Data.FullName)); bool isTargetInRange = false; var uniqueEnemyTargetsInRange = Enumerable.Empty<IMortalTarget>(); foreach (var rangeMonitor in _weaponRangeMonitorLookup.Values) { uniqueEnemyTargetsInRange = uniqueEnemyTargetsInRange.Union<IMortalTarget>(rangeMonitor.EnemyTargets); // OPTIMIZE } ICmdTarget cmdTarget = _ordersTarget as ICmdTarget; if (cmdTarget != null) { var primaryTargets = cmdTarget.UnitElementTargets.Cast<IMortalTarget>(); var primaryTargetsInRange = primaryTargets.Intersect(uniqueEnemyTargetsInRange); if (!primaryTargetsInRange.IsNullOrEmpty()) { chosenTarget = __SelectHighestPriorityTarget(primaryTargetsInRange); isTargetInRange = true; } else { D.Assert(!primaryTargets.IsNullOrEmpty(), "{0}'s primaryTargets cannot be empty when _ordersTarget is alive."); chosenTarget = __SelectHighestPriorityTarget(primaryTargets); } } else { // Planetoid D.Assert(_ordersTarget is APlanetoidModel); if (!uniqueEnemyTargetsInRange.Contains(_ordersTarget)) { if (_weaponRangeMonitorLookup.Values.Any(rangeTracker => rangeTracker.AllTargets.Contains(_ordersTarget))) { // the planetoid is not an enemy, but it is in range and therefore fair game isTargetInRange = true; } } else { // the planetoid is an enemy and in range isTargetInRange = true; } chosenTarget = _ordersTarget; } if (chosenTarget != null) { // no need for knowing about death event as primaryTarget is continuously checked while under orders to attack //D.Log("{0}'s has selected {1} as it's primary target. InRange = {2}.", Data.Name, chosenTarget.Name, isTargetInRange); } else { D.Warn("{0}'s primary target returned as null. InRange = {1}.", Data.Name, isTargetInRange); } return isTargetInRange; }
void Attacking_OnTargetDeath(IMortalTarget deadTarget) { // this can occur as a result of TakeHit but since we currently Return() right after TakeHit we shouldn't double up }
public TargetInfo(IMortalTarget planetoid, Vector3 fstOffset, float standoffDistance) { Target = planetoid; //Destination = planetoid.Position + fstOffset; _fstOffset = fstOffset; CloseEnoughDistance = planetoid.Radius + standoffDistance; //TODO should account for keepoutRadius CloseEnoughDistanceSqrd = CloseEnoughDistance * CloseEnoughDistance; }
protected void OnTargetDeath(IMortalTarget deadTarget) { //LogEvent(); RelayToCurrentState(deadTarget); }
void Moving_OnTargetDeath(IMortalTarget deadTarget) { LogEvent(); D.Assert(_moveTarget == deadTarget, "{0}.target {1} is not dead target {2}.".Inject(Data.Name, _moveTarget.FullName, deadTarget.FullName)); Return(); }
void Attacking_OnTargetDeath(IMortalTarget deadTarget) { LogEvent(); D.Assert(_attackTarget == deadTarget, "{0}.target {1} is not dead target {2}.".Inject(FullName, _attackTarget.FullName, deadTarget.FullName)); Return(); }
private IMortalTarget _primaryTarget; // IMPROVE take this previous target into account when PickPrimaryTarget() IEnumerator ExecuteAttackOrder_EnterState() { D.Log("{0}.ExecuteAttackOrder_EnterState() called.", FullName); _ordersTarget = CurrentOrder.Target; while (_ordersTarget.IsAlive) { // bool inRange = PickPrimaryTarget(out _primaryTarget); // if a primaryTarget is inRange, primary target is not null so OnWeaponReady will attack it // if not in range, then primary target will be null, so OnWeaponReady will attack other targets of opportunity, if any yield return null; } CurrentState = FacilityState.Idling; }
public bool __TryGetRandomEnemyTarget(out IMortalTarget enemyTarget) { bool result = false; enemyTarget = null; if (EnemyTargets.Count > 0) { result = true; enemyTarget = RandomExtended<IMortalTarget>.Choice(EnemyTargets); } return result; }
void ExecuteAttackOrder_ExitState() { LogEvent(); _primaryTarget = null; _ordersTarget = null; }
void Attacking_ExitState() { LogEvent(); _attackTarget = null; _attackStrength = TempGameValues.NoCombatStrength; }
/// <summary> /// Picks the highest priority target from orders. First selection criteria is inRange. /// </summary> /// <param name="chosenTarget">The chosen target from orders or null if no targets remain.</param> /// <returns> <c>true</c>if the target is in range, <c>false</c> otherwise. /// </returns> private bool PickPrimaryTarget(out IMortalTarget chosenTarget) { D.Assert(_ordersTarget != null && _ordersTarget.IsAlive, "{0}'s target from orders is null or dead.".Inject(FullName)); bool isTargetInRange = false; var uniqueEnemyTargetsInRange = Enumerable.Empty<IMortalTarget>(); foreach (var rMonitor in _weaponRangeMonitorLookup.Values) { uniqueEnemyTargetsInRange = uniqueEnemyTargetsInRange.Union<IMortalTarget>(rMonitor.EnemyTargets); // OPTIMIZE } ICmdTarget cmdTarget = _ordersTarget as ICmdTarget; if (cmdTarget != null) { var primaryTargets = cmdTarget.UnitElementTargets.Cast<IMortalTarget>(); var primaryTargetsInRange = primaryTargets.Intersect(uniqueEnemyTargetsInRange); if (!primaryTargetsInRange.IsNullOrEmpty()) { chosenTarget = SelectHighestPriorityTarget(primaryTargetsInRange); isTargetInRange = true; } else { D.Assert(!primaryTargets.IsNullOrEmpty(), "{0}'s primaryTargets cannot be empty when _ordersTarget is alive.".Inject(FullName)); chosenTarget = null; // no target as all are out of range } } else { chosenTarget = _ordersTarget; // Planetoid isTargetInRange = uniqueEnemyTargetsInRange.Contains(_ordersTarget); } if (chosenTarget != null) { // no need for knowing about death event as primaryTarget is continuously checked while under orders to attack D.Log("{0}'s has selected {1} as it's primary target. InRange = {2}.", FullName, chosenTarget.FullName, isTargetInRange); } return isTargetInRange; }
private void RemoveEnemyTarget(IMortalTarget enemyTarget) { if (EnemyTargets.Remove(enemyTarget)) { if (EnemyTargets.Count == 0) { OnEnemyInRange(false); // no longer any Enemies in range } D.Log("{0}.{1}({2:0.00}) removed Enemy Target {3} at distance {4}.", ParentFullName, _transform.name, Range, enemyTarget.FullName, Vector3.Distance(_transform.position, enemyTarget.Position)); } }
private IMortalTarget _primaryTarget; // IMPROVE take this previous target into account when PickPrimaryTarget() IEnumerator ExecuteAttackOrder_EnterState() { D.Log("{0}.ExecuteAttackOrder_EnterState() called.", FullName); TryBreakOrbit(); _ordersTarget = CurrentOrder.Target as IMortalTarget; while (_ordersTarget.IsAlive) { // once picked, _primaryTarget cannot be null when _ordersTarget is alive bool inRange = PickPrimaryTarget(out _primaryTarget); if (inRange) { D.Assert(_primaryTarget != null); // while this inRange state exists, we wait for OnWeaponReady() to be called } else { _moveTarget = _primaryTarget; _moveSpeed = Speed.Full; _orderSource = OrderSource.ElementCaptain; Call(ShipState.Moving); yield return null; // required immediately after Call() to avoid FSM bug if (_isDestinationUnreachable) { __HandleDestinationUnreachable(); yield break; } _helm.AllStop(); // stop and shoot after completing move } yield return null; } CurrentState = ShipState.Idling; }