X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=KancolleSniffer%2FModel%2FBattleInfo.cs;h=6da3a26cda9d78ee04ab7542821a85789e5f7a93;hb=f26be04d99bbb16d729ea59070e5da5deb78f00f;hp=5f20f6e2bef5b26e1a30f2542c9296fc11a7569a;hpb=36bcacbf0d331602d210607d25e6b9b59ae5131d;p=kancollesniffer%2FKancolleSniffer.git diff --git a/KancolleSniffer/Model/BattleInfo.cs b/KancolleSniffer/Model/BattleInfo.cs index 5f20f6e..6da3a26 100644 --- a/KancolleSniffer/Model/BattleInfo.cs +++ b/KancolleSniffer/Model/BattleInfo.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; using System.Linq; using KancolleSniffer.Util; -using KancolleSniffer.View; using static System.Math; namespace KancolleSniffer.Model @@ -38,6 +37,7 @@ namespace KancolleSniffer.Model Day, Night, SpNight, + AirRaid, Result, Unknown } @@ -50,32 +50,34 @@ namespace KancolleSniffer.Model public int Interception { get; set; } } - public class BattleInfo + public class BattleInfo : Sniffer.IPort { private readonly ShipInfo _shipInfo; private readonly ItemInfo _itemInfo; + private readonly AirBase _airBase; private Fleet _fleet; private Record[] _friend; private Record[] _guard; private Record[] _enemy; private Record[] _enemyGuard; private readonly List _escapingShips = new List(); - private bool _lastCell; + private bool _safeCell; public BattleState BattleState { get; set; } public int[] Formation { get; private set; } - public int[] FighterPower { get; private set; } + public Range FighterPower { get; private set; } public EnemyFighterPower EnemyFighterPower { get; private set; } public int AirControlLevel { get; private set; } public BattleResultRank ResultRank { get; private set; } public RankPair DisplayedResultRank { get; } = new RankPair(); - public BattleResult Result { get; set; } + public BattleResult Result { get; private set; } public bool EnemyIsCombined => _enemyGuard.Length > 0; - public List AirBattleResults { get; } = new List(); + public AirBattleResult AirBattleResult { get; } + public int SupportType { get; private set; } public class RankPair { - public char Assumed { get; set; } + public char Assumed { get; set; } = 'X'; public char Actual { get; set; } public bool IsError => Assumed != Actual; } @@ -92,62 +94,135 @@ namespace KancolleSniffer.Model public Combined Enemy { get; set; } } - public BattleInfo(ShipInfo shipInfo, ItemInfo itemInfo) + public BattleInfo(ShipInfo shipInfo, ItemInfo itemInfo, AirBase airBase) { _shipInfo = shipInfo; _itemInfo = itemInfo; + _airBase = airBase; + AirBattleResult = new AirBattleResult(GetAirFireShipName, GetItemNames); + } + + private string GetAirFireShipName(int idx) + { + return idx < _friend.Length ? _friend[idx].Name : _guard[idx - 6].Name; + } + + private string[] GetItemNames(int[] ids) + { + return ids.Select(id => _itemInfo.GetSpecByItemId(id).Name).ToArray(); + } + + public void Port() + { + CleanupResult(); + _safeCell = false; + BattleState = BattleState.None; } public void InspectBattle(string url, string request, dynamic json) { - if (json.api_formation()) - Formation = ((dynamic[])json.api_formation).Select(f => f is string ? (int)int.Parse(f) : (int)f) - .ToArray(); - AirControlLevel = CheckAirControlLevel(json); - ShowResult(false); // 昼戦の結果を夜戦のときに表示する - SetupResult(request, json, url.Contains("practice")); - FighterPower = CalcFighterPower(); - EnemyFighterPower = CalcEnemyFighterPower(json); + SetFormation(json); + SetSupportType(json); + ClearDamagedShipWarning(); + ShowResult(); // 昼戦の結果を夜戦のときに表示する + SetupDamageRecord(request, json, url.Contains("practice")); + SetFighterPower(); + SetEnemyFighterPower(); BattleState = url.Contains("sp_midnight") ? BattleState.SpNight : url.Contains("midnight") ? BattleState.Night : BattleState.Day; + if (BattleState != BattleState.Night) + { + AirBattleResult.Clear(); + SetAirControlLevel(json); + } CalcDamage(json); ResultRank = url.Contains("/ld_") ? CalcLdResultRank() : CalcResultRank(); SetResult(); } - public static int DeckId(dynamic json) + private void SetFormation(dynamic json) + { + if (json.api_formation()) + Formation = (int[])json.api_formation; + } + + private void SetAirControlLevel(dynamic json) + { + AirControlLevel = -1; + if (!json.api_kouku()) + return; + var stage1 = json.api_kouku.api_stage1; + if (stage1 == null || stage1.api_f_count == 0 && stage1.api_e_count == 0) + return; + AirControlLevel = (int)stage1.api_disp_seiku; + } + + private void SetSupportType(dynamic json) { - if (json.api_dock_id()) // 昼戦はtypoしている - return (int)json.api_dock_id - 1; - if (json.api_deck_id is string) // 通常の夜戦と連合艦隊(味方のみ)では文字列 - return int.Parse(json.api_deck_id) - 1; - return (int)json.api_deck_id - 1; + SupportType = json.api_support_flag() ? (int)json.api_support_flag : + json.api_n_support_flag() ? (int)json.api_n_support_flag : 0; } - private void SetupResult(string request, dynamic json, bool practice) + private void SetupDamageRecord(string request, dynamic json, bool practice) { if (_friend != null) return; _shipInfo.SaveBattleStartStatus(); - var fleets = _shipInfo.Fleets; - _fleet = fleets[DeckId(json)]; + SetupFriendDamageRecord(request, json, practice); + SetupEnemyDamageRecord(json, practice); + } + + private void SetupFriendDamageRecord(string request, dynamic json, bool practice) + { + _fleet = _shipInfo.Fleets[(int)json.api_deck_id - 1]; FlagshipRecovery(request, _fleet.ActualShips[0]); _friend = Record.Setup(_fleet.ActualShips, practice); _guard = json.api_f_nowhps_combined() - ? Record.Setup(fleets[1].ActualShips, practice) + ? Record.Setup(_shipInfo.Fleets[1].ActualShips, practice) : new Record[0]; + SetEscapedFlag(json); + } + + /// + /// EscapedはShipStatusにあるがBattleBriefTestの用のログにはShipStatusがないので、 + /// ここで戦闘用のAPIを元に設定する。 + /// + private void SetEscapedFlag(dynamic json) + { + if (json.api_escape_idx()) + { + foreach (int idx in json.api_escape_idx) + _friend[idx - 1].Escaped = true; + } + if (json.api_escape_idx_combined()) + { + foreach (int idx in json.api_escape_idx_combined) + _guard[idx - 1].Escaped = true; + } + } + + private void SetupEnemyDamageRecord(dynamic json, bool practice) + { _enemy = Record.Setup((int[])json.api_e_nowhps, - ((int[])json.api_ship_ke).Select(_shipInfo.GetSpec).ToArray(), - ((int[][])json.api_eSlot).Select(slot => slot.Select(_itemInfo.GetSpecByItemId).ToArray()).ToArray(), - practice); + EnemyShipSpecs(json.api_ship_ke), + EnemySlots(json.api_eSlot), practice); _enemyGuard = json.api_ship_ke_combined() ? Record.Setup((int[])json.api_e_nowhps_combined, - ((int[])json.api_ship_ke_combined).Select(_shipInfo.GetSpec).ToArray(), - ((int[][])json.api_eSlot).Select(slot => slot.Select(_itemInfo.GetSpecByItemId).ToArray()) - .ToArray(), practice) + EnemyShipSpecs(json.api_ship_ke_combined), + EnemySlots(json.api_eSlot_combined), practice) : new Record[0]; } + private ShipSpec[] EnemyShipSpecs(dynamic ships) + { + return ((int[])ships).Select(_shipInfo.GetSpec).ToArray(); + } + + private ItemSpec[][] EnemySlots(dynamic slots) + { + return ((int[][])slots).Select(slot => slot.Select(_itemInfo.GetSpecByItemId).ToArray()).ToArray(); + } + private void SetResult() { Result = new BattleResult @@ -202,65 +277,147 @@ namespace KancolleSniffer.Model } } - public void CleanupResult() + private void CleanupResult() { _friend = null; - _lastCell = false; } - private int CheckAirControlLevel(dynamic json) + private void SetFighterPower() { - if (!json.api_kouku()) - return -1; - var stage1 = json.api_kouku.api_stage1; - if (stage1 == null) - return -1; - if (stage1.api_f_count == 0 && stage1.api_e_count == 0) - return -1; - return (int)stage1.api_disp_seiku; + var fleets = _shipInfo.Fleets; + FighterPower = _guard.Length > 0 && _enemyGuard.Length > 0 + ? fleets[0].FighterPower + fleets[1].FighterPower + : _fleet.FighterPower; } - private int[] CalcFighterPower() + private void SetEnemyFighterPower() { - var fleets = _shipInfo.Fleets; - if (_guard.Length > 0 && _enemyGuard.Length > 0) - return fleets[0].FighterPower.Zip(fleets[1].FighterPower, (a, b) => a + b).ToArray(); - return _fleet.FighterPower; - } - - private EnemyFighterPower CalcEnemyFighterPower(dynamic json) - { - var result = new EnemyFighterPower(); - var ships = (int[])json.api_ship_ke; - if (json.api_ship_ke_combined() && _guard.Length > 0) - ships = ships.Concat((int[])json.api_ship_ke_combined).ToArray(); - var maxEq = ships.SelectMany(id => - { - var r = _shipInfo.GetSpec(id).MaxEq; - if (r != null) - return r; - result.HasUnknown = true; - return new int[5]; - }); - var equips = ((int[][])json.api_eSlot).SelectMany(x => x); - if (json.api_eSlot_combined() && _guard.Length > 0) - equips = equips.Concat(((int[][])json.api_eSlot_combined).SelectMany(x => x)); - foreach (var entry in from slot in equips.Zip(maxEq, (id, max) => new {id, max}) - let spec = _itemInfo.GetSpecByItemId(slot.id) - let perSlot = (int)Floor(spec.AntiAir * Sqrt(slot.max)) - select new {spec, perSlot}) - { - if (entry.spec.CanAirCombat) - result.AirCombat += entry.perSlot; - if (entry.spec.IsAircraft) - result.Interception += entry.perSlot; + EnemyFighterPower = new EnemyFighterPower(); + foreach (var record in _guard.Length == 0 ? _enemy : _enemy.Concat(_enemyGuard)) + { + var ship = record.SnapShot; + if (ship.Spec.MaxEq == null) + { + EnemyFighterPower.HasUnknown = true; + continue; + } + foreach (var entry in ship.Slot.Zip(ship.Spec.MaxEq, (item, maxEq) => new {item.Spec, maxEq})) + { + var perSlot = (int)Floor(entry.Spec.AntiAir * Sqrt(entry.maxEq)); + if (entry.Spec.CanAirCombat) + EnemyFighterPower.AirCombat += perSlot; + if (entry.Spec.IsAircraft) + EnemyFighterPower.Interception += perSlot; + } + } + } + + public void InspectMapStart(dynamic json) + { + InspectMapNext(json); + } + + public void InspectMapNext(dynamic json) + { + SetSafeCell(json); + BattleState = BattleState.None; + if (!json.api_destruction_battle()) + return; + InspectAirRaidBattle((int)json.api_maparea_id, json.api_destruction_battle); + } + + private void SetSafeCell(dynamic json) + { + var map = (int)json.api_maparea_id * 1000 + (int)json.api_mapinfo_no * 100 + (int)json.api_no; + _safeCell = + (int)json.api_next == 0 || // last cell + map switch + { + 1613 => true, // 1-6-B + 1611 => true, // 1-6-D + 1616 => true, // 1-6-D + 2202 => true, // 2-2-B + 3102 => true, // 3-1-B + 3201 => true, // 3-2-A + 4206 => true, // 4-2-F + 5302 => true, // 5-3-B + _ => false + }; + } + + private void InspectAirRaidBattle(int areaId, dynamic json) + { + SetFormation(json); + var attack = json.api_air_base_attack; + var stage1 = attack.api_stage1; + AirControlLevel = (int)stage1.api_disp_seiku; + var ships = (ShipStatus[])CreateShipsForAirBase(json); + _friend = Record.Setup(ships, false); + _guard = new Record[0]; + FighterPower = _airBase.GetAirBase(areaId).CalcInterceptionFighterPower(); + SetupEnemyDamageRecord(json, false); + SetEnemyFighterPower(); + BattleState = BattleState.AirRaid; + AirBattleResult.Clear(); + AirBattleResult.Add(json.api_air_base_attack, "空襲"); + CalcKoukuDamage(json.api_air_base_attack); + SetAirRaidResultRank(json); + SetResult(); + CleanupResult(); + } + + private ShipStatus[] CreateShipsForAirBase(dynamic json) + { + var nowHps = (int[])json.api_f_nowhps; + var maxHps = (int[])json.api_f_maxhps; + var maxEq = new[] {18, 18, 18, 18}; + var ships = nowHps.Select((hp, n) => new ShipStatus + { + Id = 1, + Spec = new ShipSpec {Name = "基地航空隊" + (n + 1), GetMaxEq = () => maxEq}, + NowHp = nowHps[n], + MaxHp = maxHps[n] + }).ToArray(); + var planes = json.api_air_base_attack.api_map_squadron_plane; + if (planes == null) + return ships; + foreach (KeyValuePair entry in planes) + { + var num = int.Parse(entry.Key) - 1; + var slot = new List(); + var onSlot = new List(); + foreach (var plane in entry.Value) + { + slot.Add(new ItemStatus {Id = 1, Spec = _itemInfo.GetSpecByItemId((int)plane.api_mst_id)}); + onSlot.Add((int)plane.api_count); + } + ships[num].Slot = slot; + ships[num].OnSlot = onSlot.ToArray(); + } + return ships; + } + + private void SetAirRaidResultRank(dynamic json) + { + switch ((int)json.api_lost_kind) + { + case 1: + ResultRank = BattleResultRank.A; + break; + case 2: + ResultRank = BattleResultRank.B; + break; + case 3: + ResultRank = BattleResultRank.C; + break; + case 4: + ResultRank = BattleResultRank.S; + break; } - return result; } private void CalcDamage(dynamic json) { - AirBattleResults.Clear(); foreach (KeyValuePair kv in json) { if (kv.Value == null) @@ -268,11 +425,11 @@ namespace KancolleSniffer.Model switch (kv.Key) { case "api_air_base_injection": - AddAirBattleResult(kv.Value, "AB噴式"); + AirBattleResult.Add(kv.Value, "AB噴式"); CalcKoukuDamage(kv.Value); break; case "api_injection_kouku": - AddAirBattleResult(kv.Value, "噴式"); + AirBattleResult.Add(kv.Value, "噴式"); CalcKoukuDamage(kv.Value); break; case "api_air_base_attack": @@ -288,11 +445,11 @@ namespace KancolleSniffer.Model CalcDamageByTurn(kv.Value); break; case "api_kouku": - AddAirBattleResult(kv.Value, "航空戦"); + AirBattleResult.Add(kv.Value, "航空戦"); CalcKoukuDamage(kv.Value); break; case "api_kouku2": - AddAirBattleResult(kv.Value, "航空戦2"); + AirBattleResult.Add(kv.Value, "航空戦2"); CalcKoukuDamage(kv.Value); break; case "api_support_info": @@ -343,7 +500,7 @@ namespace KancolleSniffer.Model var i = 1; foreach (var entry in json) { - AddAirBattleResult(entry, "基地" + i++); + AirBattleResult.Add(entry, "基地" + i++); CalcKoukuDamage(entry); } } @@ -353,52 +510,6 @@ namespace KancolleSniffer.Model CalcDamageByTurn(json.api_hougeki, true); } - private void AddAirBattleResult(dynamic json, string phaseName) - { - var stage1 = json.api_stage1; - if (stage1 == null || (stage1.api_f_count == 0 && stage1.api_e_count == 0)) - return; - var result = new AirBattleResult - { - PhaseName = phaseName, - AirControlLevel = json.api_stage1.api_disp_seiku() ? (int)json.api_stage1.api_disp_seiku : 0, - Stage1 = new AirBattleResult.StageResult - { - FriendCount = (int)json.api_stage1.api_f_count, - FriendLost = (int)json.api_stage1.api_f_lostcount, - EnemyCount = (int)json.api_stage1.api_e_count, - EnemyLost = (int)json.api_stage1.api_e_lostcount - }, - Stage2 = json.api_stage2 == null - ? new AirBattleResult.StageResult - { - FriendCount = 0, - FriendLost = 0, - EnemyCount = 0, - EnemyLost = 0 - } - : new AirBattleResult.StageResult - { - FriendCount = (int)json.api_stage2.api_f_count, - FriendLost = (int)json.api_stage2.api_f_lostcount, - EnemyCount = (int)json.api_stage2.api_e_count, - EnemyLost = (int)json.api_stage2.api_e_lostcount - } - }; - if (json.api_stage2 != null && json.api_stage2.api_air_fire()) - { - var airFire = json.api_stage2.api_air_fire; - var idx = (int)airFire.api_idx; - result.AirFire = new AirBattleResult.AirFireResult - { - ShipName = idx < _friend.Length ? _friend[idx].Name : _guard[idx - 6].Name, - Kind = (int)airFire.api_kind, - Items = ((int[])airFire.api_use_items).Select(id => _itemInfo.GetSpecByItemId(id).Name).ToArray() - }; - } - AirBattleResults.Add(result); - } - private void CalcKoukuDamage(dynamic json) { if (json.api_stage3() && json.api_stage3 != null) @@ -451,42 +562,71 @@ namespace KancolleSniffer.Model return; var eFlags = (int[])json.api_at_eflag; - var sources = (int[])json.api_at_list; - var types = json.api_at_type() ? (int[])json.api_at_type : (int[])json.api_sp_list; + var night = json.api_sp_list(); + var types = night ? (int[])json.api_sp_list : (int[])json.api_at_type; var targets = (int[][])json.api_df_list; var damages = (int[][])json.api_damage; - var records = new[] {new Record[12], new Record[12]}; - Array.Copy(_friend, records[1], _friend.Length); - Array.Copy(_guard, 0, records[1], 6, _guard.Length); - Array.Copy(_enemy, records[0], _enemy.Length); - Array.Copy(_enemyGuard, 0, records[0], 6, _enemyGuard.Length); + var records = new BothRecord(_friend, _guard, _enemy, _enemyGuard); for (var turn = 0; turn < eFlags.Length; turn++) { if (ignoreFriendDamage && eFlags[turn] == 1) continue; - if (types[turn] == 100 || types[turn] == 101) // Nelson Touchと長門一斉射 - records[eFlags[turn] ^ 1][sources[turn]].TriggerSpecialAttack(); + if (IsSpecialAttack(types[turn])) + { + var pos = night && _guard.Length > 0 ? 6 : 0; // 連合第二の僚艦夜戦突撃は6 + records.TriggerSpecialAttack(1, pos); + } for (var shot = 0; shot < targets[turn].Length; shot++) { var target = targets[turn][shot]; var damage = damages[turn][shot]; if (target == -1 || damage == -1) continue; - records[eFlags[turn]][target].ApplyDamage(damage); + records.ApplyDamage(eFlags[turn], target, damage); } - foreach (var ship in records[1]) - ship?.CheckDamageControl(); + records.CheckDamageControl(); } } - public void InspectMapStart(dynamic json) + private bool IsSpecialAttack(int type) { - InspectMapNext(json); + // 100: Nelson Touch + // 101: 長門一斉射 + // 102: 陸奥一斉射 + // 104: 金剛僚艦夜戦突撃 + // 200: 瑞雲一体攻撃 + // 201: 海陸立体攻撃 + return type >= 100 && type < 200; } - public void InspectMapNext(dynamic json) + private class BothRecord { - _lastCell = (int)json.api_next == 0; + private readonly Record[][] _records; + + public BothRecord(Record[] friend, Record[] guard, Record[] enemy, Record[] enemyGuard) + { + _records = new[] {new Record[12], new Record[12]}; + Array.Copy(friend, _records[1], friend.Length); + Array.Copy(guard, 0, _records[1], 6, guard.Length); + Array.Copy(enemy, _records[0], enemy.Length); + Array.Copy(enemyGuard, 0, _records[0], 6, enemyGuard.Length); + } + + public void TriggerSpecialAttack(int side, int index) + { + _records[side][index].TriggerSpecialAttack(); + } + + public void ApplyDamage(int side, int index, int damage) + { + _records[side][index].ApplyDamage(damage); + } + + public void CheckDamageControl() + { + foreach (var ship in _records[1]) + ship?.CheckDamageControl(); + } } public void InspectBattleResult(dynamic json) @@ -494,7 +634,8 @@ namespace KancolleSniffer.Model BattleState = BattleState.Result; if (_friend == null) return; - ShowResult(!_lastCell); + ShowResult(); + SetDamagedShipWarning(); _shipInfo.SaveBattleResult(); _shipInfo.DropShipId = json.api_get_ship() ? (int)json.api_get_ship.api_ship_id : -1; VerifyResultRank(json); @@ -507,12 +648,12 @@ namespace KancolleSniffer.Model BattleState = BattleState.Result; if (_friend == null) return; - ShowResult(false); + ShowResult(); VerifyResultRank(json); CleanupResult(); } - private void ShowResult(bool warnDamagedShip = true) + private void ShowResult() { if (_friend == null) return; @@ -522,10 +663,18 @@ namespace KancolleSniffer.Model : _fleet.ActualShips; foreach (var entry in ships.Zip(_friend.Concat(_guard), (ship, now) => new {ship, now})) entry.now.UpdateShipStatus(entry.ship); - if (warnDamagedShip) - _shipInfo.SetBadlyDamagedShips(); - else - _shipInfo.ClearBadlyDamagedShips(); + } + + private void SetDamagedShipWarning() + { + if (_safeCell) + return; + _shipInfo.SetBadlyDamagedShips(); + } + + private void ClearDamagedShipWarning() + { + _shipInfo.ClearBadlyDamagedShips(); } private void VerifyResultRank(dynamic json) @@ -540,7 +689,7 @@ namespace KancolleSniffer.Model DisplayedResultRank.Actual = actual; } - public void SetEscapeShips(dynamic json) + private void SetEscapeShips(dynamic json) { _escapingShips.Clear(); if (!json.api_escape_flag() || (int)json.api_escape_flag == 0) @@ -570,14 +719,15 @@ namespace KancolleSniffer.Model private bool _practice; public ShipStatus SnapShot => (ShipStatus)_status.Clone(); public int NowHp => _status.NowHp; - public bool Escaped => _status.Escaped; + public bool Escaped { get; set; } public ShipStatus.Damage DamageLevel => _status.DamageLevel; public string Name => _status.Name; public int StartHp { get; private set; } public static Record[] Setup(IEnumerable ships, bool practice) => - (from s in ships - select new Record {_status = (ShipStatus)s.Clone(), _practice = practice, StartHp = s.NowHp}).ToArray(); + (from s in ships + select new Record {_status = (ShipStatus)s.Clone(), _practice = practice, StartHp = s.NowHp}) + .ToArray(); public static Record[] Setup(int[] nowHps, ShipSpec[] specs, ItemSpec[][] slots, bool practice) { @@ -634,78 +784,69 @@ namespace KancolleSniffer.Model ship.NowHp = NowHp; ship.Slot = _status.Slot; ship.SlotEx = _status.SlotEx; - ship.SpecialAttack = _status.SpecialAttack == ShipStatus.Attack.Fire - ? ShipStatus.Attack.Fired - : ShipStatus.Attack.None; + if (_status.SpecialAttack == ShipStatus.Attack.Fire) + ship.SpecialAttack = ShipStatus.Attack.Fired; } } private BattleResultRank CalcLdResultRank() { - var combined = _friend.Concat(_guard).Where(r => !r.Escaped).ToArray(); - var friendGauge = combined.Sum(r => r.StartHp - r.NowHp); - var friendGaugeRate = Floor((double)friendGauge / combined.Sum(r => r.StartHp) * 100); + var friend = new ResultRankParams(_friend.Concat(_guard).ToArray()); - if (friendGauge <= 0) + if (friend.Gauge <= 0) return BattleResultRank.P; - if (friendGaugeRate < 10) + if (friend.GaugeRate < 10) return BattleResultRank.A; - if (friendGaugeRate < 20) + if (friend.GaugeRate < 20) return BattleResultRank.B; - if (friendGaugeRate < 50) + if (friend.GaugeRate < 50) return BattleResultRank.C; - if (friendGaugeRate < 80) + if (friend.GaugeRate < 80) return BattleResultRank.D; return BattleResultRank.E; } private BattleResultRank CalcResultRank() { - var friend = _friend.Concat(_guard).ToArray(); - var enemy = _enemy.Concat(_enemyGuard).ToArray(); - - var friendCount = friend.Length; - var friendStartHpTotal = 0; - var friendNowHpTotal = 0; - var friendSunk = 0; - foreach (var ship in friend) + var friend = new ResultRankParams(_friend.Concat(_guard).ToArray()); + var enemy = new ResultRankParams(_enemy.Concat(_enemyGuard).ToArray()); + if (friend.Sunk == 0 && enemy.Sunk == enemy.Count) { - if (ship.Escaped) - continue; - friendStartHpTotal += ship.StartHp; - friendNowHpTotal += ship.NowHp; - if (ship.NowHp == 0) - friendSunk++; - } - var friendGaugeRate = (int)((double)(friendStartHpTotal - friendNowHpTotal) / friendStartHpTotal * 100); - - var enemyCount = enemy.Length; - var enemyStartHpTotal = enemy.Sum(r => r.StartHp); - var enemyNowHpTotal = enemy.Sum(r => r.NowHp); - var enemySunk = enemy.Count(r => r.NowHp == 0); - var enemyGaugeRate = (int)((double)(enemyStartHpTotal - enemyNowHpTotal) / enemyStartHpTotal * 100); - - if (friendSunk == 0 && enemySunk == enemyCount) - { - if (friendNowHpTotal >= friendStartHpTotal) + if (friend.Gauge <= 0) return BattleResultRank.P; return BattleResultRank.S; } - if (friendSunk == 0 && enemySunk >= (int)(enemyCount * 0.7) && enemyCount > 1) + if (friend.Sunk == 0 && enemy.Sunk >= (int)(enemy.Count * 0.7) && enemy.Count > 1) return BattleResultRank.A; - if (friendSunk < enemySunk && enemy[0].NowHp == 0) + if (friend.Sunk < enemy.Sunk && _enemy[0].NowHp == 0) return BattleResultRank.B; - if (friendCount == 1 && friend[0].DamageLevel == ShipStatus.Damage.Badly) + if (friend.Count == 1 && _friend[0].DamageLevel == ShipStatus.Damage.Badly) return BattleResultRank.D; - if (enemyGaugeRate > friendGaugeRate * 2.5) + if (enemy.GaugeRate > friend.GaugeRate * 2.5) return BattleResultRank.B; - if (enemyGaugeRate > friendGaugeRate * 0.9) + if (enemy.GaugeRate > friend.GaugeRate * 0.9) return BattleResultRank.C; - if (friendCount > 1 && friendCount - 1 == friendSunk) + if (friend.Count > 1 && friend.Count - 1 == friend.Sunk) return BattleResultRank.E; return BattleResultRank.D; } + private class ResultRankParams + { + public readonly int Count; + public readonly int Sunk; + public readonly int Gauge; + public readonly int GaugeRate; + + public ResultRankParams(Record[] records) + { + Count = records.Length; + Sunk = records.Count(r => r.NowHp == 0); + Gauge = records.Sum(r => r.StartHp - r.NowHp); + GaugeRate = (int)((double)Gauge / records.Sum(r => r.Escaped ? 0 : r.StartHp) * 100); + } + } + /// /// テスト専用 ///