public GameFormationActor(GameFormation f, IServiceProvider services) : base(services) { this.formation = f; this.formationId = f.FormationId; this.formationName = f.FormationName; }
/// <summary> /// Generates a <see cref="GameFormation"/> with a single <see cref="GameUnit"/> via <see cref="GenerateTestUnit"/> /// and assigns a default, simple set of <see cref="VolleyOrders"/> to it for Volley 1; also assigns the new GameUnit /// a set of <see cref="GameUnitFireAllocation"/> orders to match up with the <see cref="FireOrder"/>s. /// </summary> /// <param name="id">Desired ID of the new formation</param> /// <param name="name">Desired name of the new formation</param> /// <param name="unitList">Reference to a list of GameUnits, so that the Formation's new GameUnit can be added to it.</param> /// <param name="targetFormationId">Optionally, specify the ID of a target Formation for this Formation's Orders to specify. Default is 0.</param> /// <returns>The new Formation with included <see cref="GameUnitFormationInfo"/> for the new GameUnit. Side Effect: adds the new GameUnit to <paramref name="unitList"/></returns> public static GameFormation GenerateTestFormation(int id, string name, ref List <GameUnit> unitList, int targetFormationId = 0) { GameUnit u = GenerateTestUnit(id: 1, name: $"{name}-1"); unitList.Add(u); var f = new GameFormation() { FormationId = id, FormationName = name, MaxThrust = 99, Orders = new List <VolleyOrders>(), PlayerId = 0, }; f.Units = new List <GameUnitFormationInfo>() { new GameUnitFormationInfo(u, f) }; var fOrder = new VolleyOrders() { Volley = 1, EvasionDice = 2, SpeedDice = 4, FiringOrders = new List <FireOrder>() { new FireOrder() { TargetID = targetFormationId, FireType = "Normal", Priority = "Primary", TargetFormationName = string.Empty, DiceAssigned = 0 } }, ManeuveringOrders = new List <ManeuverOrder>() { new ManeuverOrder() { TargetID = targetFormationId, ManeuverType = "Close", Priority = "Primary" } } }; u.FireAllocation = new List <GameUnitFireAllocation>() { new GameUnitFireAllocation(volley: 1, fireConId: u.Electronics.OfType <FireControlSystem>().First().Id, fireMode: "Normal", priority: "Primary", weaponIds: u.Weapons.Select(w => w.Id).ToList()) }; f.Orders.Add(fOrder); return(f); }
private static List <string> GenerateOrdersReadout(GameFormation f, List <GameUnit> allUnits, List <GameFormation> formations) { List <string> readout = new List <string>(); foreach (var volleyOrder in f.Orders) { readout.AddRange(WrapDecorated(volleyOrder.ToString(), ReadoutWidth, "* ", " *", 5)); readout.AddRange(PrintReadoutCollection(string.Empty, volleyOrder.ManeuveringOrders, true)); foreach (var fire in volleyOrder.FiringOrders) { var leadString = itemLeadString; var fireOrderString = ToTitleCase($"{fire.FireType} Order: '{fire.Priority}' -- Target: [{fire.TargetID}] {fire.TargetFormationName}{(fire.DiceAssigned > 0 ? $" ({fire.DiceAssigned}D)" : string.Empty)}"); readout.AddRange(WrapDecorated(fireOrderString, ReadoutWidth, itemLeadString, " *", 5)); foreach (var unit in f.Units) { var unitForOrder = allUnits.FirstOrDefault(x => x.IdNumeric == unit.UnitId); if (unitForOrder != null) { var unitOrderFireAllocations = unitForOrder.FireAllocation.Where(fireAlloc => (fireAlloc.Volley == volleyOrder.Volley || fireAlloc.Volley == 0) && fireAlloc.Priority.ToLowerInvariant() == fire.Priority.ToLowerInvariant()); foreach (var allocation in unitOrderFireAllocations) { var fc = unitForOrder.AllSystems.FirstOrDefault(afc => afc.Id == allocation.FireConId) ?? new FireControlSystem() { Status = UnitSystemStatus.Operational }; // TODO: BUG: reporting "Operational" even for damaged FireCon sometimes, see default XML: ANS Glory, Volley 2, Secondary / FireCon ID 6 should be Damaged var line = new List <string>() { $"> {unit.UnitName} -- FC{fc.Id}({fc.StatusString})" }; foreach (var w in allocation.WeaponIDs) { var wep = unitForOrder.Weapons.First(uw => uw.Id == w); line.Add($">> {wep.ToString()}"); } readout.AddRange(PrintReadoutCollection(string.Empty, line, true)); } } } } } return(readout); }
private static List <string> GenerateFormationReadout(GameFormation f, List <GameUnit> allUnits, List <GamePlayer> players) { var readout = new List <string>(); var player = players.Where(p => p.Id == f.PlayerId.ToString()).FirstOrDefault() ?? new GamePlayer() { Name = "Unknown Player" }; var playerStrings = new List <string>() { $"Player {player.Id}", player.Team, (player.Key <= 0 ? player.Name : $"{player.Name} [{player.Key}]"), player.Email, string.IsNullOrWhiteSpace(player.Objectives) ? null : $"\"{player.Objectives}\"" }.Where(s => !string.IsNullOrWhiteSpace(s)); readout.AddRange(WrapDecorated(string.Join(" -- ", playerStrings), ReadoutWidth, "* ", " *", 5)); readout.AddRange(WrapDecorated($"Area Screen Rating '{f.GetFormationAreaScreenRating()}'", ReadoutWidth, "* ", " *")); readout.AddRange(WrapDecorated($"MaxThrust '{f.MaxThrust}'", ReadoutWidth, "* ", " *")); readout.AddRange(WrapDecorated($"Units ({f.Units.Count})", ReadoutWidth, "* ", " *")); foreach (var u in f.Units) { var uR = allUnits.Where(ur => ur.IdNumeric == u.UnitId).First(); var unitString = $"- {uR.ToString()} ({uR.Status}) -- Thrust {uR.GetCurrentThrust()}"; if (uR.GetCurrentThrust() > f.MaxThrust) { unitString += $" ({f.MaxThrust}+{u.ExtraThrust})"; } if (u.IsFormationFlag) { unitString += $" -- Flagship"; } unitString += $" -- HitChance {f.GetHitChancePercentage(u.UnitId):0.##}%"; readout.AddRange(WrapDecorated(unitString, ReadoutWidth, "* ", " *", 5)); readout.AddRange(PrintReadoutCollection("Fire Allocations", uR.FireAllocation)); } return(readout); }
private static void ExecuteManeuversForFormation(int currentVolley, GameFormation f, GameState gameState) { VolleyOrders orders = f.GetOrdersForVolley(currentVolley); foreach (var o in orders.GetSortedManeuveringOrders()) { var target = gameState.Formations.Where(t => t.FormationId == o.TargetID).FirstOrDefault(); var speed = Math.Max(0, orders.SpeedSuccesses + ManeuverOrder.GetManeuverModifier(o.Priority)); if (target == null || o.ManeuverType == Constants.PassiveManeuverType) { // Bail early if the maneuver is a passive one, e.g. "Maintain" // Bail early if the maneuver is not against a valid target Id (e.g. "Target 0" default orders or orders against Formations that have been destroyed) continue; } int rangeShift = o.CalculateRangeShift(currentVolley, f, orders.SpeedSuccesses, target); gameState.DistanceGraph.UpdateDistance(f, target, rangeShift); } }
protected override IList <GameEvent> ReceiveWeaponAttackEvent(GameEvent arg) { var result = new List <GameEvent>(); var evt = arg as WeaponAttackEvent ?? throw ReceiverArgumentMismatch(nameof(arg), arg.GetType(), MethodBase.GetCurrentMethod().Name, typeof(AttackEvent)); // Unit receives event if: // a) WeaponAttack is assigned to this Unit's Formation // b) Attack's percentile roll is within this Unit's PercentileRange if (evt.TargetingData.Target.FormationId == this.unitFormationInfo.FormationId && this.unitFormationInfo.CoversPercentile(evt.UnitAssignmentPercentile)) { var target = evt.TargetingData.Target.UnitActor.unitFormationInfo; GameFormation targetFormation = target.GetFormationReference(); GameUnit targetUnit = target.GetUnitReference(); GameFormation attackerFormation = this.unitFormationInfo.GetFormationReference(); GameUnit attackerUnit = this.unitFormationInfo.GetUnitReference(); int firingRange = evt.TargetingData.FormationRange; result.Add(new UnitStatusEvent() { Description = $"UnitStatus: [{this.UnitId}]{this.UnitName}", Message = $"[{targetFormation.FormationId}]{targetFormation.FormationName}:[{targetUnit.IdNumeric}]{targetUnit.Name}" + $" covers percentile range {this.unitFormationInfo.PercentileLowerBound}-{this.unitFormationInfo.PercentileUpperBound}," + $" so incoming attack with percentile roll {evt.UnitAssignmentPercentile} targets it.", Exchange = evt.Exchange, Volley = evt.Volley }); WeaponSystem weapon = evt.AttackData.Weapon; // TODO: Add ability to override this from AttackData and/or TargetingData? Constants.DamageType effectiveDamageType = weapon.GetDamageType(); int evasionDRM = -1 * targetFormation.GetOrdersForVolley(evt.Volley).EvasionSuccesses; int otherDRM = targetFormation.GetDRMVersusWeaponType(weapon.GetType()) + targetUnit.GetDRMVersusWeaponType(weapon.GetType()); var localScreens = targetUnit.GetLocalScreenRating(); var areaScreens = targetFormation.GetFormationAreaScreenRating(); ScreenRating totalScreenRating = ScreenRating.Combine(localScreens, areaScreens); DamageResult weaponAttackResult = this.ResolveWeaponAttack(weapon, firingRange, totalScreenRating, evasionDRM, otherDRM); var statusMsg = $"[{attackerUnit.IdNumeric}]{attackerUnit.Name} fires [{weapon.Id}]{weapon.SystemName} at [{targetUnit.IdNumeric}]{targetUnit.Name}" + $"\n\t\t -- Net modifiers: Range {firingRange}" + $", Screen {weapon.FinalizeScreenValue(totalScreenRating)}" + $", Evasion DRM {weapon.FinalizeEvasionDRM(evasionDRM)}" + $", Other DRM {otherDRM}" + $"\n\t\t -- Rolls {weaponAttackResult.RollString()}" + $"\n\t\t -- Deals {weaponAttackResult.ToString()}"; result.Add(new UnitStatusEvent() { Description = $"UnitStatus: [{this.UnitId}]{this.UnitName}", Message = statusMsg, Exchange = evt.Exchange, Volley = evt.Volley }); } return(result); }