From e704bf36cd2cb9c3e80dadf9159eb38694f24ebd Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 4 Jul 2024 13:36:40 +0900 Subject: [PATCH 01/38] WIP --- .../Data/Battle/BattleAirBattle.cs | 53 -- .../Data/Battle/BattleAirRaid.cs | 41 - .../Data/Battle/BattleBaseAirRaid.cs | 38 - .../Data/Battle/BattleCombinedAirBattle.cs | 52 -- .../Data/Battle/BattleCombinedAirRaid.cs | 43 - .../Data/Battle/BattleCombinedEachDay.cs | 61 -- .../Data/Battle/BattleCombinedEachWater.cs | 61 -- .../Data/Battle/BattleCombinedNightOnly.cs | 44 - .../Data/Battle/BattleCombinedNormalDay.cs | 61 -- .../Data/Battle/BattleCombinedNormalNight.cs | 41 - .../Data/Battle/BattleCombinedRadar.cs | 35 - .../Data/Battle/BattleCombinedWater.cs | 59 -- ElectronicObserver/Data/Battle/BattleData.cs | 167 ---- ElectronicObserver/Data/Battle/BattleDay.cs | 23 - .../Data/Battle/BattleDayFromNight.cs | 26 - .../Data/Battle/BattleEnemyCombinedDay.cs | 60 -- .../Battle/BattleEnemyCombinedDayFromNight.cs | 74 -- .../Data/Battle/BattleEnemyCombinedNight.cs | 42 - .../Data/Battle/BattleManager.cs | 186 +++-- ElectronicObserver/Data/Battle/BattleNight.cs | 14 - .../Data/Battle/BattleNightOnly.cs | 44 - .../Data/Battle/BattleNormalDay.cs | 61 -- .../Data/Battle/BattleNormalDayFromNight.cs | 74 -- .../Data/Battle/BattleNormalNight.cs | 41 - .../Data/Battle/BattleNormalRadar.cs | 35 - .../Data/Battle/BattlePracticeDay.cs | 52 -- .../Data/Battle/BattlePracticeNight.cs | 37 - .../Data/Battle/BattleResultData.cs | 250 ------ .../Data/Battle/Detail/BattleDetail.cs | 488 ------------ .../Battle/Detail/BattleDetailDescriptor.cs | 751 ------------------ .../Data/Battle/Phase/PhaseAirBattle.cs | 109 --- .../Data/Battle/Phase/PhaseAirBattleBase.cs | 272 ------- .../Data/Battle/Phase/PhaseBase.cs | 126 --- .../Data/Battle/Phase/PhaseBaseAirAttack.cs | 149 ---- .../Data/Battle/Phase/PhaseBaseAirRaid.cs | 64 -- .../Battle/Phase/PhaseFriendlyAirBattle.cs | 68 -- .../Battle/Phase/PhaseFriendlyShelling.cs | 242 ------ .../Battle/Phase/PhaseFriendlySupportInfo.cs | 128 --- .../Data/Battle/Phase/PhaseInitial.cs | 327 -------- .../Data/Battle/Phase/PhaseJetAirBattle.cs | 105 --- .../Battle/Phase/PhaseJetBaseAirAttack.cs | 141 ---- .../Data/Battle/Phase/PhaseNightBattle.cs | 162 ---- .../Data/Battle/Phase/PhaseNightInitial.cs | 214 ----- .../Data/Battle/Phase/PhaseOpeningASW.cs | 20 - .../Data/Battle/Phase/PhaseRadar.cs | 18 - .../Data/Battle/Phase/PhaseSearching.cs | 64 -- .../Data/Battle/Phase/PhaseShelling.cs | 136 ---- .../Data/Battle/Phase/PhaseSupport.cs | 168 ---- .../Data/Battle/Phase/PhaseTorpedo.cs | 147 ---- ElectronicObserver/Data/Constants.cs | 73 +- ElectronicObserver/Data/FleetManager.cs | 6 +- .../Data/Quest/QuestProgressManager.cs | 8 +- .../Battle/TsunDbBattleData.cs | 2 +- .../Data/TsunDbSubmission/EnemyComp.cs | 8 +- .../Data/TsunDbSubmission/ShipDrop.cs | 2 +- .../Data/TsunDbSubmission/ShipDropLoc.cs | 2 +- ElectronicObserver/Notifier/NotifierDamage.cs | 6 +- .../Resource/Record/EnemyFleetRecord.cs | 6 +- .../Resource/Record/ShipParameterRecord.cs | 42 +- .../DataExport/DataExportHelper.cs | 42 +- .../Sortie/Battle/AirBattleData.cs | 9 +- .../Sortie/Battle/BattleAirBattle.cs | 2 +- .../Sortie/Battle/BattleBaseAirRaid.cs | 2 +- .../Sortie/Battle/BattleCombinedAirBattle.cs | 2 +- .../Sortie/Battle/BattleData.cs | 11 +- .../Sortie/Battle/BattlePracticeDay.cs | 7 +- .../Sortie/Battle/DayBattleData.cs | 2 +- .../Sortie/Battle/DayFromNightBattleData.cs | 17 +- .../Sortie/Battle/FirstBattleData.cs | 2 +- .../Sortie/Battle/Interfaces/IAirBattle.cs | 9 + .../Battle/Interfaces/IBaseAirAttack.cs | 8 + .../Sortie/Battle/Interfaces/INightInitial.cs | 8 + .../Battle/Interfaces/IPhaseAirBattle.cs | 29 + .../Sortie/Battle/NightBattleData.cs | 5 +- .../Sortie/Battle/NightOnlyBattleData.cs | 2 +- .../Sortie/Battle/Phase/PhaseAirBattleBase.cs | 96 ++- .../Battle/Phase/PhaseBaseAirAttackUnit.cs | 4 +- .../Sortie/Battle/Phase/PhaseBaseAirRaid.cs | 70 +- .../Sortie/Battle/Phase/PhaseFactory.cs | 4 +- .../Sortie/Battle/Phase/PhaseInitial.cs | 49 +- .../Sortie/Battle/Phase/PhaseJetAirBattle.cs | 9 +- .../Battle/Phase/PhaseJetBaseAirAttack.cs | 5 +- .../Phase/PhaseNightBattleAttackViewModel.cs | 3 + .../Sortie/Battle/Phase/PhaseNightInitial.cs | 6 +- .../Sortie/Battle/Phase/PhaseSearching.cs | 19 +- .../Phase/PhaseShellingAttackViewModel.cs | 3 +- .../Sortie/Battle/Phase/PhaseSupport.cs | 16 +- .../Sortie/Battle/RadarBattleData.cs | 5 +- .../Sortie/Node/BattleNode.cs | 6 +- .../Sortie/Node/BattleResult.cs | 4 +- .../SortieCostViewer/AirBaseCostCalculator.cs | 6 +- .../SortieCostViewer/SupplyCostCalculator.cs | 2 +- .../Window/Wpf/Battle/BattleViewModel.cs | 286 +++---- .../Window/Wpf/Compass/CompassViewModel.cs | 20 +- .../ViewModels/EnemyFleetElementViewModel.cs | 2 +- .../InformationView/InformationViewModel.cs | 2 +- 96 files changed, 634 insertions(+), 5969 deletions(-) delete mode 100644 ElectronicObserver/Data/Battle/BattleAirBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleAirRaid.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleBaseAirRaid.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedAirBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedAirRaid.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedEachDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedEachWater.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedNightOnly.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedNormalDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedNormalNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedRadar.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleCombinedWater.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleData.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleDayFromNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleEnemyCombinedDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleEnemyCombinedDayFromNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleEnemyCombinedNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNightOnly.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNormalDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNormalDayFromNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNormalNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleNormalRadar.cs delete mode 100644 ElectronicObserver/Data/Battle/BattlePracticeDay.cs delete mode 100644 ElectronicObserver/Data/Battle/BattlePracticeNight.cs delete mode 100644 ElectronicObserver/Data/Battle/BattleResultData.cs delete mode 100644 ElectronicObserver/Data/Battle/Detail/BattleDetail.cs delete mode 100644 ElectronicObserver/Data/Battle/Detail/BattleDetailDescriptor.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseAirBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseAirBattleBase.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseBase.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseBaseAirAttack.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseBaseAirRaid.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseFriendlyAirBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseFriendlyShelling.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseFriendlySupportInfo.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseInitial.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseJetAirBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseJetBaseAirAttack.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseNightBattle.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseNightInitial.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseOpeningASW.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseRadar.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseSearching.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseShelling.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseSupport.cs delete mode 100644 ElectronicObserver/Data/Battle/Phase/PhaseTorpedo.cs create mode 100644 ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IAirBattle.cs create mode 100644 ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IBaseAirAttack.cs create mode 100644 ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/INightInitial.cs create mode 100644 ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IPhaseAirBattle.cs diff --git a/ElectronicObserver/Data/Battle/BattleAirBattle.cs b/ElectronicObserver/Data/Battle/BattleAirBattle.cs deleted file mode 100644 index 889f90200..000000000 --- a/ElectronicObserver/Data/Battle/BattleAirBattle.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 通常艦隊 航空戦 -/// -public class BattleAirBattle : BattleDay -{ - - public PhaseAirBattle AirBattle2 { get; protected set; } - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "第一次航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - AirBattle2 = new PhaseAirBattle(this, "第二次航空戦", "2"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - public override string APIName => "api_req_sortie/airbattle"; - - public override string BattleName => ConstantsRes.Title_NormalFleetAirBattle; - - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return AirBattle2; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleAirRaid.cs b/ElectronicObserver/Data/Battle/BattleAirRaid.cs deleted file mode 100644 index b79927d1a..000000000 --- a/ElectronicObserver/Data/Battle/BattleAirRaid.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 通常艦隊 長距離空襲戦 -/// -public class BattleAirRaid : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - AirBattle = new PhaseAirBattle(this, "空襲戦"); - // 支援は出ないものとする - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - public override string APIName => "api_req_sortie/ld_airbattle"; - - public override string BattleName => ConstantsRes.Title_NormalFleetAirRaid; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return AirBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleBaseAirRaid.cs b/ElectronicObserver/Data/Battle/BattleBaseAirRaid.cs deleted file mode 100644 index 16fdd816f..000000000 --- a/ElectronicObserver/Data/Battle/BattleBaseAirRaid.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 基地防空戦 -/// -public class BattleBaseAirRaid : BattleDay -{ - - public PhaseBaseAirRaid BaseAirRaid { get; protected set; } - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - BaseAirRaid = new PhaseBaseAirRaid(this, "防空戦"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_map/next"; - - public override string BattleName => ConstantsRes.Title_BaseAirRaid; - - public override bool IsBaseAirRaid => true; - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return BaseAirRaid; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedAirBattle.cs b/ElectronicObserver/Data/Battle/BattleCombinedAirBattle.cs deleted file mode 100644 index ca2e7969b..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedAirBattle.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 連合艦隊 vs 通常艦隊 航空戦 -/// -public class BattleCombinedAirBattle : BattleDay -{ - - public PhaseAirBattle AirBattle2 { get; protected set; } - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "第一次航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - AirBattle2 = new PhaseAirBattle(this, "第二次航空戦", "2"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/airbattle"; - - public override string BattleName => ConstantsRes.Title_CombinedFleetAirBattle; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return AirBattle2; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedAirRaid.cs b/ElectronicObserver/Data/Battle/BattleCombinedAirRaid.cs deleted file mode 100644 index d99780ae1..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedAirRaid.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 連合艦隊 vs 通常艦隊 長距離空襲戦 -/// -public class BattleCombinedAirRaid : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - AirBattle = new PhaseAirBattle(this, "空襲戦"); - // 支援はないものとする - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/ld_airbattle"; - - public override string BattleName => ConstantsRes.Title_CombinedFleetAirRaid; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return AirBattle; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedEachDay.cs b/ElectronicObserver/Data/Battle/BattleCombinedEachDay.cs deleted file mode 100644 index 328b89731..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedEachDay.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 機動部隊 vs 連合艦隊 昼戦 -/// -public class BattleCombinedEachDay : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 3); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 4, "3"); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/each_battle"; - - public override string BattleName => ConstantsRes.Title_CombinedEachDay; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Torpedo; - yield return Shelling3; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedEachWater.cs b/ElectronicObserver/Data/Battle/BattleCombinedEachWater.cs deleted file mode 100644 index c73a0768d..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedEachWater.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 水上部隊 vs 連合艦隊 昼戦 -/// -public class BattleCombinedEachWater : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 3, "3"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 4); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/each_battle_water"; - - public override string BattleName => ConstantsRes.Title_CombinedEachWater; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Shelling3; - yield return Torpedo; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedNightOnly.cs b/ElectronicObserver/Data/Battle/BattleCombinedNightOnly.cs deleted file mode 100644 index 1c41aa73c..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedNightOnly.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 連合艦隊 vs 通常艦隊 開幕夜戦 -/// -public class BattleCombinedNightOnly : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", true); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - Support = new PhaseSupport(this, "夜間支援攻撃", true); - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - - - public override string APIName => "api_req_combined_battle/sp_midnight"; - - public override string BattleName => ConstantsRes.Title_CombinedNightOnly; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return Support; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedNormalDay.cs b/ElectronicObserver/Data/Battle/BattleCombinedNormalDay.cs deleted file mode 100644 index 18e43da3d..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedNormalDay.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 機動部隊 vs 通常艦隊 昼戦 -/// -public class BattleCombinedNormalDay : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 2); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 3, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 4, "3"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/battle"; - - public override string BattleName => ConstantsRes.Title_CombinedNormalDay; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Torpedo; - yield return Shelling2; - yield return Shelling3; - } - -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedNormalNight.cs b/ElectronicObserver/Data/Battle/BattleCombinedNormalNight.cs deleted file mode 100644 index 012745588..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedNormalNight.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 連合艦隊 vs 通常艦隊 夜戦 -/// -public class BattleCombinedNormalNight : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", true); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - // 支援なし? - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - - public override string APIName => "api_req_combined_battle/midnight_battle"; - - public override string BattleName => BattleRes.CombinedFleetNightBattle; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedRadar.cs b/ElectronicObserver/Data/Battle/BattleCombinedRadar.cs deleted file mode 100644 index a2c12bc00..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedRadar.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 連合艦隊 vs 通常艦隊 レーダー射撃 -/// -public class BattleCombinedRadar : BattleDay -{ - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - Shelling1 = new PhaseRadar(this, "レーダー射撃"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - public override string APIName => "api_req_combined_battle/ld_shooting"; - - public override string BattleName => BattleRes.CombinedFleetRadarAmbush; - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; // ? - yield return JetBaseAirAttack; - yield return BaseAirAttack; - yield return Shelling1; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleCombinedWater.cs b/ElectronicObserver/Data/Battle/BattleCombinedWater.cs deleted file mode 100644 index 3be5efcfd..000000000 --- a/ElectronicObserver/Data/Battle/BattleCombinedWater.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 水上部隊 vs 通常艦隊 昼戦 -/// -public class BattleCombinedWater : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 3, "3"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 4); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/battle_water"; - - public override string BattleName => BattleRes.SuijouButaiDayBattle; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Shelling3; - yield return Torpedo; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleData.cs b/ElectronicObserver/Data/Battle/BattleData.cs deleted file mode 100644 index 8e5254653..000000000 --- a/ElectronicObserver/Data/Battle/BattleData.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 戦闘情報を保持するデータの基底です。 -/// -public abstract class BattleData : ResponseWrapper -{ - - protected int[] _resultHPs; - /// - /// 戦闘終了時の各艦のHP - /// - public ReadOnlyCollection ResultHPs => Array.AsReadOnly(_resultHPs); - - protected int[] _attackDamages; - /// - /// 各艦の与ダメージ - /// - public ReadOnlyCollection AttackDamages => Array.AsReadOnly(_attackDamages); - - - public PhaseInitial Initial { get; protected set; } - public PhaseSearching Searching { get; protected set; } - public PhaseFriendlySupportInfo FriendlySupportInfo { get; protected set; } - public PhaseSupport Support { get; protected set; } - - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - Initial = new PhaseInitial(this, BattleRes.Participant); - Searching = new PhaseSearching(this, BattleRes.PhaseSearching); - - _resultHPs = new int[24]; - Array.Copy(Initial.FriendInitialHPs, 0, _resultHPs, 0, Initial.FriendInitialHPs.Length); - Array.Copy(Initial.EnemyInitialHPs, 0, _resultHPs, 12, Initial.EnemyInitialHPs.Length); - if (Initial.FriendInitialHPsEscort != null) - Array.Copy(Initial.FriendInitialHPsEscort, 0, _resultHPs, 6, 6); - if (Initial.EnemyInitialHPsEscort != null) - Array.Copy(Initial.EnemyInitialHPsEscort, 0, _resultHPs, 18, 6); - - - - if (_attackDamages == null) - _attackDamages = new int[_resultHPs.Length]; - } - - - /// - /// MVP 取得候補艦のインデックス [0-6] - /// - public IEnumerable MVPShipIndexes - { - get - { - int memberCount = Initial.FriendFleet.Members.Count; - int max = _attackDamages.Take(memberCount).Max(); - if (max == 0) - { // 全員ノーダメージなら旗艦MVP - yield return 0; - - } - else - { - for (int i = 0; i < memberCount; i++) - { - if (_attackDamages[i] == max) - yield return i; - } - } - } - } - - - /// - /// 連合艦隊随伴艦隊の MVP 取得候補艦のインデックス [0-5] - /// - public IEnumerable MVPShipCombinedIndexes - { - get - { - int max = _attackDamages.Skip(6).Take(6).Max(); - if (max == 0) - { // 全員ノーダメージなら旗艦MVP - yield return 0; - - } - else - { - for (int i = 0; i < 6; i++) - { - if (_attackDamages[i + 6] == max) - yield return i; - } - } - } - } - - - /// - /// 前回の戦闘データからパラメータを引き継ぎます。 - /// - internal void TakeOverParameters(BattleData prev) - { - _attackDamages = (int[])prev._attackDamages.Clone(); - } - - - - /// - /// 対応しているAPIの名前を取得します。 - /// - public abstract string APIName { get; } - - /// - /// 戦闘形態の名称 - /// - public abstract string BattleName { get; } - - - public virtual bool IsPractice => false; - public virtual bool IsFriendCombined => Initial.IsFriendCombined; - public virtual bool IsEnemyCombined => Initial.IsEnemyCombined; - public virtual bool IsBaseAirRaid => false; - - - - /// - /// すべての戦闘詳細データを取得します。 - /// - public string GetBattleDetail() - { - return GetBattleDetail(-1); - } - - /// - /// 指定したインデックスの艦の戦闘詳細データを取得します。 - /// - /// インデックス。[0-23] - public string GetBattleDetail(int index) - { - var sb = new StringBuilder(); - - foreach (var phase in GetPhases()) - { - string bd = phase.GetBattleDetail(index); - - if (!string.IsNullOrEmpty(bd)) - { - sb.AppendLine("== " + phase.Title + " ==").Append(bd); - } - } - return sb.ToString(); - } - - - public abstract IEnumerable GetPhases(); - -} diff --git a/ElectronicObserver/Data/Battle/BattleDay.cs b/ElectronicObserver/Data/Battle/BattleDay.cs deleted file mode 100644 index c0704ea80..000000000 --- a/ElectronicObserver/Data/Battle/BattleDay.cs +++ /dev/null @@ -1,23 +0,0 @@ -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 昼戦の基底クラス -/// -public abstract class BattleDay : BattleData -{ - - public PhaseJetBaseAirAttack JetBaseAirAttack { get; protected set; } - public PhaseJetAirBattle JetAirBattle { get; protected set; } - public PhaseBaseAirAttack BaseAirAttack { get; protected set; } - public PhaseFriendlyAirBattle FriendlyAirBattle { get; protected set; } - public PhaseAirBattle AirBattle { get; protected set; } - public PhaseOpeningASW OpeningASW { get; protected set; } - public PhaseTorpedo OpeningTorpedo { get; protected set; } - public PhaseShelling Shelling1 { get; protected set; } - public PhaseShelling Shelling2 { get; protected set; } - public PhaseShelling Shelling3 { get; protected set; } - public PhaseTorpedo Torpedo { get; protected set; } - -} diff --git a/ElectronicObserver/Data/Battle/BattleDayFromNight.cs b/ElectronicObserver/Data/Battle/BattleDayFromNight.cs deleted file mode 100644 index 0092a751d..000000000 --- a/ElectronicObserver/Data/Battle/BattleDayFromNight.cs +++ /dev/null @@ -1,26 +0,0 @@ -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 夜昼戦 -/// -public abstract class BattleDayFromNight : BattleNight -{ - - public PhaseSupport NightSupport { get; protected set; } - public PhaseNightBattle NightBattle2 { get; protected set; } - - public bool NextToDay => (int)RawData.api_day_flag != 0; - - public PhaseJetBaseAirAttack JetBaseAirAttack { get; protected set; } - public PhaseJetAirBattle JetAirBattle { get; protected set; } - public PhaseBaseAirAttack BaseAirAttack { get; protected set; } - public PhaseAirBattle AirBattle { get; protected set; } - public PhaseOpeningASW OpeningASW { get; protected set; } - public PhaseTorpedo OpeningTorpedo { get; protected set; } - public PhaseShelling Shelling1 { get; protected set; } - public PhaseShelling Shelling2 { get; protected set; } - public PhaseTorpedo Torpedo { get; protected set; } - -} diff --git a/ElectronicObserver/Data/Battle/BattleEnemyCombinedDay.cs b/ElectronicObserver/Data/Battle/BattleEnemyCombinedDay.cs deleted file mode 100644 index d4fb52d85..000000000 --- a/ElectronicObserver/Data/Battle/BattleEnemyCombinedDay.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 連合艦隊 昼戦 -/// -public class BattleEnemyCombinedDay : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 2); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 3, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 4, "3"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_combined_battle/ec_battle"; - - public override string BattleName => ConstantsRes.Title_EnemyCombinedDay; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Torpedo; - yield return Shelling2; - yield return Shelling3; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleEnemyCombinedDayFromNight.cs b/ElectronicObserver/Data/Battle/BattleEnemyCombinedDayFromNight.cs deleted file mode 100644 index f01fa02b7..000000000 --- a/ElectronicObserver/Data/Battle/BattleEnemyCombinedDayFromNight.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常/連合艦隊 vs 連合艦隊 夜昼戦 -/// -public class BattleEnemyCombinedDayFromNight : BattleDayFromNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - NightSupport = new PhaseSupport(this, "夜間支援攻撃", true); - NightBattle = new PhaseNightBattle(this, "第一次夜戦", 1); - NightBattle2 = new PhaseNightBattle(this, "第二次夜戦", 2); - - - if (NextToDay) - { - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - Support = new PhaseSupport(this, "支援攻撃"); - // ここに友軍艦隊航空攻撃が入るかわからない - AirBattle = new PhaseAirBattle(this, "航空戦"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 3); - } - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - public override string APIName => "api_req_combined_battle/ec_night_to_day"; - - public override string BattleName => BattleRes.EnemyCombinedFleetNightDayBattle; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return NightSupport; - yield return NightBattle; - yield return NightBattle2; - - if (NextToDay) - { - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return Support; - yield return AirBattle; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Torpedo; - } - } -} diff --git a/ElectronicObserver/Data/Battle/BattleEnemyCombinedNight.cs b/ElectronicObserver/Data/Battle/BattleEnemyCombinedNight.cs deleted file mode 100644 index 743b2a80e..000000000 --- a/ElectronicObserver/Data/Battle/BattleEnemyCombinedNight.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常/連合艦隊 vs 連合艦隊 夜戦 -/// -public class BattleEnemyCombinedNight : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - // 支援なし? - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - - public override string APIName => "api_req_combined_battle/ec_midnight_battle"; - - public override string BattleName => ConstantsRes.Title_EnemyCombinedNight; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 077fafc47..f8f523f0b 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -2,11 +2,15 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserver.Data.Battle.Phase; +using ElectronicObserver.Database.KancolleApi; +using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.Resource.Record; using ElectronicObserver.Utility.Mathematics; using ElectronicObserver.Window.Dialog.QuestTrackerManager.Enums; +using ElectronicObserver.Window.Tools.SortieRecordViewer; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; using ElectronicObserverTypes; using ElectronicObserverTypes.Extensions; using ElectronicObserverTypes.Mocks; @@ -38,17 +42,17 @@ public class BattleManager : APIWrapper /// /// 昼戦データ /// - public BattleDay BattleDay { get; private set; } + public FirstBattleData BattleDay { get; private set; } /// /// 夜戦データ /// - public BattleNight BattleNight { get; private set; } + public BattleData? BattleNight { get; private set; } /// /// 戦闘結果データ /// - public BattleResultData Result { get; private set; } + public BattleResult Result { get; private set; } /// /// The battle result api doesn't report SS, so we need to evaluate it manually. @@ -126,18 +130,18 @@ public bool StartsFromNightBattle /// /// 1回目の戦闘 /// - public BattleData FirstBattle => HeavyBaseAirRaids switch + public FirstBattleData FirstBattle => HeavyBaseAirRaids switch { // first battle gets used for things like engagement // remove this part if heavy air raids get moved to BattleDay { Count: > 0 } => HeavyBaseAirRaids.Last(), - _ => StartsFromDayBattle ? BattleDay : BattleNight + _ => StartsFromDayBattle ? BattleDay : (FirstBattleData)BattleNight! }; /// /// 2回目の戦闘 /// - public BattleData SecondBattle => StartsFromDayBattle ? (BattleData)BattleNight : BattleDay; + public BattleData? SecondBattle => StartsFromDayBattle ? (BattleData)BattleNight : BattleDay; /// @@ -153,7 +157,7 @@ public bool StartsFromNightBattle /// /// 出撃中に入手したアイテム - ID と 個数 のペア /// - public Dictionary DroppedItemCount { get; internal set; } + public Dictionary DroppedItemCount { get; } = []; /// @@ -180,21 +184,24 @@ public bool StartsFromNightBattle /// /// 特殊攻撃発動回数 /// - public Dictionary SpecialAttackCount { get; private set; } + public Dictionary SpecialAttackCount { get; } = []; /// /// 記録する特殊攻撃 /// - private int[] TracedSpecialAttack { get; } = { 100, 101, 102, 103, 104, 300, 301, 302, 400, 401 }; + private List TracedSpecialAttack { get; } = [100, 101, 102, 103, 104, 300, 301, 302, 400, 401]; - - - public BattleManager() + public override void LoadFromRequest(string apiname, Dictionary data) { - DroppedItemCount = new Dictionary(); - SpecialAttackCount = new Dictionary(); - } + switch (apiname) + { + case "api_req_sortie/battle": + ResupplyUsed = data.ContainsKey("api_supply_flag") && data["api_supply_flag"] == "1"; + RationUsed = data.ContainsKey("api_ration_flag") && data["api_ration_flag"] == "1"; + break; + } + } public override void LoadFromResponse(string apiname, dynamic data) { @@ -204,6 +211,7 @@ public override void LoadFromResponse(string apiname, dynamic data) switch (apiname) { + /* case "api_req_map/start": case "api_req_map/next": BattleDay = null; @@ -375,6 +383,7 @@ public override void LoadFromResponse(string apiname, dynamic data) Result.LoadFromResponse(apiname, data); BattleFinished(); break; + */ case "api_port/port": Compass = null; @@ -393,19 +402,6 @@ public override void LoadFromResponse(string apiname, dynamic data) break; } - - } - - public override void LoadFromRequest(string apiname, Dictionary data) - { - switch (apiname) - { - case "api_req_sortie/battle": - ResupplyUsed = data.ContainsKey("api_supply_flag") && data["api_supply_flag"] == "1"; - RationUsed = data.ContainsKey("api_ration_flag") && data["api_ration_flag"] == "1"; - break; - } - } /// @@ -430,29 +426,30 @@ private void BattleFinished() } else if (IsBaseAirRaid) { - if (BattleDay is BattleBaseAirRaid { BaseAirRaid: { } airraid }) + if (BattleDay is BattleBaseAirRaid raid) { - var initialHPs = BattleDay.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0); - var damage = initialHPs.Zip(BattleDay.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); + PhaseBaseAirRaid? airraid = raid.BaseAirRaid; + List initialHPs = BattleDay.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); + int damage = initialHPs.Zip(BattleDay.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedBaseAirRaid, Compass.MapAreaID, Compass.MapInfoID, Compass.CellDisplay, - Constants.GetAirSuperiority(airraid.IsAvailable ? airraid.AirSuperiority : -1), damage, Constants.GetAirRaidDamage(Compass.AirRaidDamageKind))); + Constants.GetAirSuperiority(airraid?.AirState ?? AirState.Unknown), damage, Constants.GetAirRaidDamage(Compass.AirRaidDamageKind))); } foreach (BattleBaseAirRaid battleBaseAirRaid in HeavyBaseAirRaids) { List initialHPs = battleBaseAirRaid.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); int damage = initialHPs.Zip(battleBaseAirRaid.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); - PhaseBaseAirRaid baseAirRaid = battleBaseAirRaid.BaseAirRaid; + PhaseBaseAirRaid? baseAirRaid = battleBaseAirRaid.BaseAirRaid; - int airRaidDamageKind = (int)battleBaseAirRaid.RawData.api_lost_kind; + int airRaidDamageKind = baseAirRaid?.ApiLostKind ?? 0; Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedBaseAirRaid, Compass.MapAreaID, Compass.MapInfoID, Compass.CellDisplay, - Constants.GetAirSuperiority(baseAirRaid.IsAvailable ? baseAirRaid.AirSuperiority : -1), damage, Constants.GetAirRaidDamage(airRaidDamageKind))); + Constants.GetAirSuperiority(baseAirRaid?.AirState ?? AirState.Unknown), damage, Constants.GetAirRaidDamage(airRaidDamageKind))); } } else @@ -466,14 +463,14 @@ private void BattleFinished() // Level up if (!IsBaseAirRaid) { - var exps = Result.ExpList; - var lvup = Result.LevelUpList; - for (int i = 0; i < lvup.Length; i++) + List exps = Result.ExpList; + List> lvup = Result.LevelUpList; + for (int i = 0; i < lvup.Count; i++) { - if (lvup[i].Length >= 2 && i < exps.Length && lvup[i][0] + exps[i] >= lvup[i][1]) + if (lvup[i].Count >= 2 && i < exps.Count && lvup[i][0] + exps[i] >= lvup[i][1]) { - var ship = FirstBattle.Initial.FriendFleet.MembersInstance[i]; - int increment = Math.Max(lvup[i].Length - 2, 1); + IShipData ship = FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[i]!; + int increment = Math.Max(lvup[i].Count - 2, 1); ShipLevelUp?.Invoke(ship, ship.Level + increment); Utility.Logger.Add(2, string.Format(BattleRes.HasLeveledUp, ship.Name, ship.Level + increment)); @@ -482,14 +479,15 @@ private void BattleFinished() if (IsCombinedBattle) { - exps = Result.ExpListCombined; - lvup = Result.LevelUpListCombined; - for (int i = 0; i < lvup.Length; i++) + exps = Result.ExpListCombined!; + lvup = Result.LevelUpListCombined!; + + for (int i = 0; i < lvup.Count; i++) { - if (lvup[i].Length >= 2 && i < exps.Length && lvup[i][0] + exps[i] >= lvup[i][1]) + if (lvup[i].Count >= 2 && i < exps.Count && lvup[i][0] + exps[i] >= lvup[i][1]) { - var ship = FirstBattle.Initial.FriendFleetEscort.MembersInstance[i]; - int increment = Math.Max(lvup[i].Length - 2, 1); + IShipData ship = FirstBattle.FleetsBeforeBattle.EscortFleet!.MembersInstance[i]!; + int increment = Math.Max(lvup[i].Count - 2, 1); ShipLevelUp?.Invoke(ship, ship.Level + increment); Utility.Logger.Add(2, string.Format(BattleRes.HasLeveledUp, ship.Name, ship.Level + increment)); @@ -503,18 +501,17 @@ private void BattleFinished() //ドロップ艦記録 if (!IsPractice && !IsBaseAirRaid) { - //checkme: とてもアレな感じ - int shipID = Result.DroppedShipID; - int itemID = Result.DroppedItemID; - int eqID = Result.DroppedEquipmentID; + int shipID = (int?)Result.DroppedShipId ?? -1; + int itemID = Result.DroppedItemId ?? -1; + int eqID = Result.DroppedEquipmentId ?? -1; bool showLog = Utility.Configuration.Config.Log.ShowSpoiler; if (shipID != -1) { - IShipDataMaster ship = KCDatabase.Instance.MasterShips[shipID]; + IShipDataMaster ship = KCDatabase.Instance.MasterShips[(int)shipID]; DroppedShipCount++; IEnumerable? defaultSlot = ship.DefaultSlot?.Select(i => i switch @@ -536,22 +533,19 @@ private void BattleFinished() if (itemID != -1) { - - if (!DroppedItemCount.ContainsKey(itemID)) - DroppedItemCount.Add(itemID, 0); + DroppedItemCount.TryAdd(itemID, 0); DroppedItemCount[itemID]++; if (showLog) { - var item = KCDatabase.Instance.UseItems[itemID]; - var itemmaster = KCDatabase.Instance.MasterUseItems[itemID]; + IUseItem? item = KCDatabase.Instance.UseItems[itemID]; + IUseItemMaster? itemmaster = KCDatabase.Instance.MasterUseItems[itemID]; Utility.Logger.Add(2, string.Format(LoggerRes.ItemObtained, itemmaster?.NameTranslated ?? (BattleRes.UnknownItem + itemID), (item?.Count ?? 0) + DroppedItemCount[itemID])); } } if (eqID != -1) { - IEquipmentDataMaster eq = KCDatabase.Instance.MasterEquipments[eqID]; if (eq.UsesSlotSpace()) { @@ -577,30 +571,50 @@ private void BattleFinished() } - void IncrementSpecialAttack(BattleData bd) + void IncrementSpecialAttack(BattleData? bd) { - if (bd == null) - return; + if (bd == null) return; - foreach (var phase in bd.GetPhases()) + foreach (PhaseBase phase in bd.Phases) { - foreach (var detail in phase.BattleDetails) + switch (phase) { - int kind = detail.AttackType; + case PhaseShelling shelling: + { + foreach (PhaseShellingAttackViewModel attack in shelling.AttackDisplays + .Where(a => a.AttackerIndex.FleetFlag is FleetFlag.Player) + .Where(a => TracedSpecialAttack.Contains((int)a.AttackType))) + { + if (!SpecialAttackCount.TryAdd((int)attack.AttackType, 1)) + { + SpecialAttackCount[(int)attack.AttackType]++; + } + } + + break; + } - if (detail.AttackerIndex.IsFriend && TracedSpecialAttack.Contains(kind)) + case PhaseNightBattle night: { - if (SpecialAttackCount.ContainsKey(kind)) - SpecialAttackCount[kind]++; - else - SpecialAttackCount.Add(kind, 1); + foreach (PhaseNightBattleAttackViewModel attack in night.AttackDisplays + .Where(a => a.AttackerIndex.FleetFlag is FleetFlag.Player) + .Where(a => TracedSpecialAttack.Contains((int)a.AttackType))) + { + if (!SpecialAttackCount.TryAdd((int)attack.AttackType, 1)) + { + SpecialAttackCount[(int)attack.AttackType]++; + } + } + + break; } } } } + IncrementSpecialAttack(FirstBattle); IncrementSpecialAttack(SecondBattle); - + WriteBattleLog(); } @@ -612,23 +626,23 @@ void IncrementSpecialAttack(BattleData bd) public int PredictWinRank(out double friendrate, out double enemyrate) { BattleData activeBattle = SecondBattle ?? FirstBattle; - PhaseInitial firstInitial = FirstBattle.Initial; + BattleFleets fleetsBefore = activeBattle.FleetsBeforeBattle; List hpsAfter = activeBattle.ResultHPs.ToList(); - + BattleRankPrediction prediction = new() { - FriendlyMainFleetBefore = firstInitial.FriendFleet, - FriendlyMainFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(firstInitial.FriendFleet, hpsAfter, BattleSides.FriendMain)!, + FriendlyMainFleetBefore = fleetsBefore.Fleet, + FriendlyMainFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.Fleet, hpsAfter, BattleSides.FriendMain)!, - FriendlyEscortFleetBefore = firstInitial.FriendFleetEscort, - FriendlyEscortFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(firstInitial.FriendFleetEscort, hpsAfter, BattleSides.FriendEscort), + FriendlyEscortFleetBefore = fleetsBefore.EscortFleet, + FriendlyEscortFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.EscortFleet, hpsAfter, BattleSides.FriendEscort), - EnemyMainFleetBefore = firstInitial.EnemyFleet, - EnemyMainFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(firstInitial.EnemyFleet, hpsAfter, BattleSides.EnemyMain)!, + EnemyMainFleetBefore = fleetsBefore.EnemyFleet!, + EnemyMainFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.EnemyFleet!, hpsAfter, BattleSides.EnemyMain)!, - EnemyEscortFleetBefore = firstInitial.EnemyFleetEscort, - EnemyEscortFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(firstInitial.EnemyFleetEscort, hpsAfter, BattleSides.EnemyEscort), + EnemyEscortFleetBefore = fleetsBefore.EnemyEscortFleet, + EnemyEscortFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.EnemyEscortFleet, hpsAfter, BattleSides.EnemyEscort), }; BattleRank rank = (BattleMode & BattleModes.BattlePhaseMask) switch @@ -652,11 +666,11 @@ public bool WillNightBattleWithMainFleet() { var initial = BattleDay.Initial; int score = 0; - for (int i = 0; i < initial.EnemyInitialHPsEscort.Length; i++) + for (int i = 0; i < initial.EnemyInitialHPsEscort.Count; i++) { - if (initial.EnemyMembersEscort[i] > 0) + if (initial.EnemyMembersEscort.ToList()[i] > 0) { - double rate = (double)BattleDay.ResultHPs[BattleIndex.Get(BattleSides.EnemyEscort, i)] / initial.EnemyMaxHPsEscort[i]; + double rate = (double)BattleDay.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / initial.EnemyMaxHPsEscort.ToList()[i]; if (rate > 0.5) { @@ -702,7 +716,7 @@ private void WriteBattleLog() using (var sw = new StreamWriter(path, false, Utility.Configuration.Config.Log.FileEncoding)) { - sw.Write(BattleDetailDescriptor.GetBattleDetail(this)); + // todo sw.Write(BattleDetailDescriptor.GetBattleDetail(this)); } } diff --git a/ElectronicObserver/Data/Battle/BattleNight.cs b/ElectronicObserver/Data/Battle/BattleNight.cs deleted file mode 100644 index 9fdb9d4dd..000000000 --- a/ElectronicObserver/Data/Battle/BattleNight.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 夜戦の基底クラス -/// -public abstract class BattleNight : BattleData -{ - public PhaseNightInitial NightInitial { get; protected set; } - public PhaseFriendlyShelling FriendlyShelling { get; protected set; } - public PhaseNightBattle NightBattle { get; protected set; } - -} diff --git a/ElectronicObserver/Data/Battle/BattleNightOnly.cs b/ElectronicObserver/Data/Battle/BattleNightOnly.cs deleted file mode 100644 index 2d1bf2afb..000000000 --- a/ElectronicObserver/Data/Battle/BattleNightOnly.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常/連合艦隊 vs 通常艦隊 開幕夜戦 -/// -public class BattleNightOnly : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - Support = new PhaseSupport(this, "夜間支援攻撃", true); - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - - public override string APIName => "api_req_battle_midnight/sp_midnight"; - - public override string BattleName => ConstantsRes.Title_NightOnly; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return Support; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleNormalDay.cs b/ElectronicObserver/Data/Battle/BattleNormalDay.cs deleted file mode 100644 index c241accfa..000000000 --- a/ElectronicObserver/Data/Battle/BattleNormalDay.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 通常艦隊 昼戦 -/// -public class BattleNormalDay : BattleDay -{ - - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyAirBattle = new PhaseFriendlyAirBattle(this, "友軍支援航空攻撃"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - Support = new PhaseSupport(this, "支援攻撃"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 3, "3"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 4); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_sortie/battle"; - - public override string BattleName => ConstantsRes.Title_NormalDay; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return FriendlySupportInfo; - yield return FriendlyAirBattle; - yield return AirBattle; - yield return Support; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Shelling3; - yield return Torpedo; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleNormalDayFromNight.cs b/ElectronicObserver/Data/Battle/BattleNormalDayFromNight.cs deleted file mode 100644 index 8fef93a07..000000000 --- a/ElectronicObserver/Data/Battle/BattleNormalDayFromNight.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常/連合艦隊 vs 通常艦隊 夜昼戦 -/// -public class BattleNormalDayFromNight : BattleDayFromNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - NightSupport = new PhaseSupport(this, "夜間支援攻撃", true); - NightBattle = new PhaseNightBattle(this, "第一次夜戦", 1); - NightBattle2 = new PhaseNightBattle(this, "第二次夜戦", 2); - - - if (NextToDay) - { - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - Support = new PhaseSupport(this, "支援攻撃"); - // ここに友軍艦隊航空攻撃が来るかわからない - AirBattle = new PhaseAirBattle(this, "航空戦"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 3); - } - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - public override string APIName => "api_req_sortie/night_to_day"; - - public override string BattleName => "対通常艦隊 夜昼戦"; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return NightSupport; - yield return NightBattle; - yield return NightBattle2; - - if (NextToDay) - { - yield return JetBaseAirAttack; - yield return JetAirBattle; - yield return BaseAirAttack; - yield return Support; - yield return AirBattle; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Torpedo; - } - } -} diff --git a/ElectronicObserver/Data/Battle/BattleNormalNight.cs b/ElectronicObserver/Data/Battle/BattleNormalNight.cs deleted file mode 100644 index 4e6d1c080..000000000 --- a/ElectronicObserver/Data/Battle/BattleNormalNight.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 通常艦隊 夜戦 -/// -public class BattleNormalNight : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - FriendlySupportInfo = new PhaseFriendlySupportInfo(this, "友軍艦隊"); - FriendlyShelling = new PhaseFriendlyShelling(this, "友軍艦隊援護"); - // 支援なし? - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - - public override string APIName => "api_req_battle_midnight/battle"; - - public override string BattleName => ConstantsRes.Title_NormalNight; - - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return NightInitial; - yield return FriendlySupportInfo; - yield return FriendlyShelling; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleNormalRadar.cs b/ElectronicObserver/Data/Battle/BattleNormalRadar.cs deleted file mode 100644 index c72ff7edf..000000000 --- a/ElectronicObserver/Data/Battle/BattleNormalRadar.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 通常艦隊 vs 通常艦隊 レーダー射撃 -/// -public class BattleNormalRadar : BattleDay -{ - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetBaseAirAttack = new PhaseJetBaseAirAttack(this, "噴式基地航空隊攻撃"); - BaseAirAttack = new PhaseBaseAirAttack(this, "基地航空隊攻撃"); - Shelling1 = new PhaseRadar(this, "レーダー射撃"); - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - } - - public override string APIName => "api_req_sortie/ld_shooting"; - - public override string BattleName => "通常艦隊 レーダー射撃"; - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; // ? - yield return JetBaseAirAttack; - yield return BaseAirAttack; - yield return Shelling1; - } -} diff --git a/ElectronicObserver/Data/Battle/BattlePracticeDay.cs b/ElectronicObserver/Data/Battle/BattlePracticeDay.cs deleted file mode 100644 index a9121ee91..000000000 --- a/ElectronicObserver/Data/Battle/BattlePracticeDay.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 演習 昼戦 -/// -public class BattlePracticeDay : BattleDay -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - JetAirBattle = new PhaseJetAirBattle(this, "噴式航空戦"); - AirBattle = new PhaseAirBattle(this, "航空戦"); - OpeningASW = new PhaseOpeningASW(this, "先制対潜"); - OpeningTorpedo = new PhaseTorpedo(this, "先制雷撃", 0); - Shelling1 = new PhaseShelling(this, "第一次砲撃戦", 1, "1"); - Shelling2 = new PhaseShelling(this, "第二次砲撃戦", 2, "2"); - Shelling3 = new PhaseShelling(this, "第三次砲撃戦", 3, "3"); - Torpedo = new PhaseTorpedo(this, "雷撃戦", 4); - - - foreach (var phase in GetPhases()) - phase.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_practice/battle"; - - public override string BattleName => ConstantsRes.Title_PracticeDay; - - public override bool IsPractice => true; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return Searching; - yield return JetAirBattle; - yield return AirBattle; - yield return OpeningASW; - yield return OpeningTorpedo; - yield return Shelling1; - yield return Shelling2; - yield return Shelling3; - yield return Torpedo; - } -} diff --git a/ElectronicObserver/Data/Battle/BattlePracticeNight.cs b/ElectronicObserver/Data/Battle/BattlePracticeNight.cs deleted file mode 100644 index c009f2797..000000000 --- a/ElectronicObserver/Data/Battle/BattlePracticeNight.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using ElectronicObserver.Data.Battle.Phase; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 演習 夜戦 -/// -public class BattlePracticeNight : BattleNight -{ - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - NightInitial = new PhaseNightInitial(this, "夜戦開始", false); - NightBattle = new PhaseNightBattle(this, "夜戦", 0); - - NightBattle.EmulateBattle(_resultHPs, _attackDamages); - - } - - - public override string APIName => "api_req_practice/midnight_battle"; - - public override string BattleName => ConstantsRes.Title_PracticeNight; - - public override bool IsPractice => true; - - - public override IEnumerable GetPhases() - { - yield return Initial; - yield return NightInitial; - yield return NightBattle; - } -} diff --git a/ElectronicObserver/Data/Battle/BattleResultData.cs b/ElectronicObserver/Data/Battle/BattleResultData.cs deleted file mode 100644 index 4707a7e3d..000000000 --- a/ElectronicObserver/Data/Battle/BattleResultData.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ElectronicObserver.Data.Battle; - -/// -/// 戦闘結果のデータを扱います。 -/// -public class BattleResultData : ResponseWrapper -{ - - /// - /// 現在保存されているAPIの名前 - /// - private string _APIName { get; set; } - - - - // :( - /// - /// 演習の結果かどうか - /// - private bool IsPractice => _APIName == "api_req_practice/battle_result"; - - - - - /// - /// 勝利ランク - /// - public string Rank => RawData.api_win_rank; - - /// - /// 獲得提督経験値 - /// - public int AdmiralExp => (int)RawData.api_get_exp; - - /// - /// MVP艦のインデックス (1-6, -1=なし) - /// - public int MVPIndex => (int)RawData.api_mvp; - - /// - /// 随伴艦隊 MVP 艦のインデックス (1-6, -1=なし) - /// - public int MVPIndexCombined => RawData.api_mvp_combined() && RawData.api_mvp_combined != null ? (int)RawData.api_mvp_combined : -1; - - - /// - /// 獲得基本経験値 - /// - public int BaseExp => (int)RawData.api_get_base_exp; - - - /// - /// 主力艦隊の入手経験値リスト [0-5] - /// 欠番は -1 - /// - public int[] ExpList - { - get - { - if (!RawData.api_get_ship_exp()) - return new int[6]; - - var src = (int[])RawData.api_get_ship_exp; - var ret = new int[Math.Max(src.Length - 1, 6)]; - Array.Copy(src, 1, ret, 0, src.Length - 1); - return ret; - } - } - - /// - /// 随伴艦隊の入手経験値リスト [0-5] - /// 欠番は -1 - /// - public int[] ExpListCombined - { - get - { - if (!RawData.api_get_ship_exp_combined()) - return new int[6]; - - var src = (int[])RawData.api_get_ship_exp_combined; - var ret = new int[Math.Max(src.Length - 1, 6)]; - Array.Copy(src, 1, ret, 0, src.Length - 1); - return ret; - } - } - - /// - /// 主力艦隊のレベルアップリスト [所属艦船数] - /// [0]=現在のexp, [1]=(あれば)次のレベルの経験値, [2]=(あれば)その次のレベルの経験値, ... - /// - public int[][] LevelUpList - { - get - { - if (!RawData.api_get_exp_lvup()) - return new int[0][]; - - var ret = new List(); - foreach (var data in RawData.api_get_exp_lvup) - { - ret.Add((int[])data); - } - return ret.ToArray(); - } - } - - /// - /// 随伴艦隊のレベルアップリスト [所属艦船数] - /// [0]=現在のexp, [1]=(あれば)次のレベルの経験値, [2]=(あれば)その次のレベルの経験値, ... - /// - public int[][] LevelUpListCombined - { - get - { - if (!RawData.api_get_exp_lvup_combined()) - return new int[0][]; - - var ret = new List(); - foreach (var data in RawData.api_get_exp_lvup_combined) - { - ret.Add((int[])data); - } - return ret.ToArray(); - } - } - - - //lostflag - - - /// - /// 敵艦隊名 - /// - public string EnemyFleetName => RawData.api_enemy_info.api_deck_name; - - //undone: 複数の battleresult に対応させる - - - /// - /// ドロップした艦船のID - /// - public int DroppedShipID - { - get - { - if (IsPractice) - return -1; - if ((int)RawData.api_get_flag[1] == 0) - return -1; - - return (int)RawData.api_get_ship.api_ship_id; - } - } - - - /// - /// ドロップしたアイテムのID - /// - public int DroppedItemID - { - get - { - if (IsPractice) - return -1; - if ((int)RawData.api_get_flag[0] == 0) - return -1; - - return (int)RawData.api_get_useitem.api_useitem_id; - } - } - - - /// - /// ドロップした装備のID(現在未使用) - /// - public int DroppedEquipmentID - { - get - { - if (IsPractice) - return -1; - if ((int)RawData.api_get_flag[2] == 0) - return -1; - - return (int)RawData.api_get_slotitem.api_slotitem_id; - } - } - - - - - /// - /// 護衛退避可能か - /// - public bool CanEscape - { - get - { - if (!RawData.api_escape()) - { - return false; - } - else - { - return (int)RawData.api_escape != 0; - } - } - } - - /// - /// 退避艦のインデックス - /// - public IEnumerable EscapingShipIndex - { - get - { - if (!RawData.api_escape()) - { - return null; - } - else if (!RawData.api_escape.api_tow_idx()) - { - return new int[1] { (int)RawData.api_escape.api_escape_idx[0] }; - } - else - { - return new int[2] { (int)RawData.api_escape.api_escape_idx[0], (int)RawData.api_escape.api_tow_idx[0] }; - } - - } - } - - /// - /// api_first_clear is 1 when clearing a map for the first time - /// for maps with gauges it's 1 every time the last gauge is cleared - /// - public bool IsFirstClear => RawData.api_first_clear > 0; - - public override void LoadFromResponse(string apiname, dynamic data) - { - base.LoadFromResponse(apiname, (object)data); - - _APIName = apiname; - - } -} diff --git a/ElectronicObserver/Data/Battle/Detail/BattleDetail.cs b/ElectronicObserver/Data/Battle/Detail/BattleDetail.cs deleted file mode 100644 index 571d8eb5d..000000000 --- a/ElectronicObserver/Data/Battle/Detail/BattleDetail.cs +++ /dev/null @@ -1,488 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using ElectronicObserver.Utility.Data; -using ElectronicObserverTypes; -using ElectronicObserverTypes.Attacks; - -namespace ElectronicObserver.Data.Battle.Detail; - -/// -/// 戦闘詳細のデータを保持します。 -/// -public abstract class BattleDetail -{ - - public double[] RawDamages { get; protected set; } - public int[] Damages { get; protected set; } - public bool[] GuardsFlagship { get; protected set; } - public CriticalType[] CriticalTypes { get; protected set; } - public int AttackType { get; protected set; } - public int[] EquipmentIDs { get; protected set; } - public int DefenderHP { get; protected set; } - - public IShipDataMaster Attacker { get; protected set; } - public IShipDataMaster Defender { get; protected set; } - - - /// 攻撃側インデックス - public BattleIndex AttackerIndex { get; protected set; } - - /// 防御側インデックス - public BattleIndex DefenderIndex { get; protected set; } - - - protected readonly BattleData Battle; - - - public enum CriticalType - { - Miss = 0, - Hit = 1, - Critical = 2, - Invalid = -1 - } - - - /// 戦闘情報。 - /// 攻撃側のインデックス。 - /// 防御側のインデックス。 - /// ダメージの配列。 - /// 命中判定の配列。 - /// 攻撃種別。 - /// 防御側の攻撃を受ける直前のHP。 - public BattleDetail(BattleData bd, BattleIndex attackerIndex, BattleIndex defenderIndex, double[] damages, int[] criticalTypes, int attackType, int[] equipmentIDs, int defenderHP) - { - Battle = bd; - - AttackerIndex = attackerIndex; - DefenderIndex = defenderIndex; - RawDamages = damages; - Damages = damages.Select(dmg => (int)dmg).ToArray(); - GuardsFlagship = damages.Select(dmg => dmg != Math.Floor(dmg)).ToArray(); - CriticalTypes = criticalTypes.Select(i => (CriticalType)i).ToArray(); - AttackType = attackType; - EquipmentIDs = equipmentIDs; - DefenderHP = defenderHP; - - } - - - protected int[] SetAttacker() - { - if (AttackerIndex < 0) - { - Attacker = null; - return null; - } - else - { - switch (AttackerIndex.Side) - { - case BattleSides.FriendMain: - { - var atk = Battle.Initial.FriendFleet.MembersInstance[AttackerIndex.Index]; - Attacker = atk.MasterShip; - return atk.AllSlotMaster.ToArray(); - } - - case BattleSides.FriendEscort: - { - var atk = Battle.Initial.FriendFleetEscort.MembersInstance[AttackerIndex.Index]; - Attacker = atk.MasterShip; - return atk.AllSlotMaster.ToArray(); - } - - case BattleSides.EnemyMain: - Attacker = Battle.Initial.EnemyMembersInstance[AttackerIndex.Index]; - return Battle.Initial.EnemySlots[AttackerIndex.Index]; - - case BattleSides.EnemyEscort: - Attacker = Battle.Initial.EnemyMembersEscortInstance[AttackerIndex.Index]; - return Battle.Initial.EnemySlotsEscort[AttackerIndex.Index]; - - default: - throw new NotSupportedException(); - } - } - } - - protected void SetDefender() - { - if (Battle.IsBaseAirRaid) - { - Defender = null; - } - else - { - switch (DefenderIndex.Side) - { - case BattleSides.FriendMain: - Defender = Battle.Initial.FriendFleet.MembersInstance[DefenderIndex.Index].MasterShip; - break; - - case BattleSides.FriendEscort: - Defender = Battle.Initial.FriendFleetEscort.MembersInstance[DefenderIndex.Index].MasterShip; - break; - - case BattleSides.EnemyMain: - Defender = Battle.Initial.EnemyMembersInstance[DefenderIndex.Index]; - break; - - case BattleSides.EnemyEscort: - Defender = Battle.Initial.EnemyMembersEscortInstance[DefenderIndex.Index]; - break; - } - } - - } - - - - /// - /// 戦闘詳細の情報を出力します。 - /// - public override string ToString() - { - - StringBuilder builder = new StringBuilder(); - - - if (Battle.IsPractice) - builder.AppendFormat("{0}{1} → {2}{3}", - Attacker == null ? "" : AttackerIndex.IsFriend ? $"{BattleRes.Friendly} " : $"{BattleRes.Enemy} ", GetAttackerName(), - DefenderIndex.IsFriend ? $"{BattleRes.Friendly} " : $"{BattleRes.Enemy} ", GetDefenderName() - ).AppendLine(); - else - builder.AppendFormat("{0} → {1}", GetAttackerName(), GetDefenderName()).AppendLine(); - - - if (AttackType >= 0) - builder.Append("[").Append(GetAttackKind()).Append("] "); - - /*// - if ( EquipmentIDs != null ) { - var eqs = EquipmentIDs.Select( id => KCDatabase.Instance.MasterEquipments[id] ).Where( eq => eq != null ).Select( eq => eq.Name ); - if ( eqs.Any() ) - builder.Append( "(" ).Append( string.Join( ", ", eqs ) ).Append( ") " ); - } - //*/ - - for (int i = 0; i < Damages.Length; i++) - { - if (CriticalTypes[i] == CriticalType.Invalid) // カットイン(主砲/主砲)、カットイン(主砲/副砲)時に発生する - continue; - - if (i > 0) - builder.Append(" , "); - - if (GuardsFlagship[i]) - builder.Append($"<{BattleRes.Protected}> "); - - switch (CriticalTypes[i]) - { - case CriticalType.Miss: - builder.Append("Miss"); - break; - case CriticalType.Hit: - builder.Append(Damages[i]).Append(" Dmg"); - break; - case CriticalType.Critical: - builder.Append(Damages[i]).Append(" Critical!"); - break; - } - - } - - - int beforeHP = Math.Max(DefenderHP, 0); - int afterHP = Math.Max(DefenderHP - Damages.Sum(), 0); - if (beforeHP != afterHP) - builder.AppendFormat(" ( {0} → {1} )", beforeHP, afterHP); - - - - builder.AppendLine(); - - - // damage control - if (beforeHP > 0 && afterHP <= 0 && DefenderIndex.IsFriend && !Battle.IsPractice && !Battle.IsBaseAirRaid) - { - var defender = (DefenderIndex.Side == BattleSides.FriendEscort ? Battle.Initial.FriendFleetEscort : Battle.Initial.FriendFleet) - ?.MembersInstance?.ElementAtOrDefault(DefenderIndex.Index); - if (defender != null) - { - int id = defender.DamageControlID; - - if (id == 42) - builder.AppendFormat($" {BattleRes.DameconActivated} HP{0}", (int)(defender.HPMax * 0.2)).AppendLine(); - - else if (id == 43) - builder.AppendFormat($" {BattleRes.GoddessActivated} HP{0}", defender.HPMax).AppendLine(); - - } - } - return builder.ToString(); - } - - - protected virtual string GetAttackerName() - { - int index = AttackerIndex.Index + 1 + (AttackerIndex.IsEscort ? 6 : 0); - - if (Attacker == null) - return "#" + index; - - return Attacker.NameWithClass + " #" + index; - } - - protected virtual string GetDefenderName() - { - int index = DefenderIndex.Index + 1 + (DefenderIndex.IsEscort ? 6 : 0); - - if (Defender == null) - return "#" + index; - return Defender.NameWithClass + " #" + index; - } - - protected abstract int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID); - protected abstract string GetAttackKind(); - -} - - -/// -/// 昼戦の戦闘詳細データを保持します。 -/// -public class BattleDayDetail : BattleDetail -{ - - public BattleDayDetail(BattleData bd, BattleIndex attackerId, BattleIndex defenderId, double[] damages, int[] criticalTypes, int attackType, int[] equipmentIDs, int defenderHP) - : base(bd, attackerId, defenderId, damages, criticalTypes, attackType, equipmentIDs, defenderHP) - { - var attackerSlots = SetAttacker(); - SetDefender(); - - if (AttackType == 0 && Attacker != null) - AttackType = CaclulateAttackKind(attackerSlots, Attacker.ShipID, Defender.ShipID); - - } - - protected override int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID) - { - return (int)Calculator.GetDayAttackKind(slots, attackerShipID, defenderShipID, false); - } - - protected override string GetAttackKind() - { - return DayAttack.AttackDisplay((DayAttackKind)AttackType); - } -} - -/// -/// 支援攻撃の戦闘詳細データを保持します。 -/// -public class BattleSupportDetail : BattleDetail -{ - - public BattleSupportDetail(BattleData bd, BattleIndex defenderId, double damage, int criticalType, int attackType, int defenderHP) - : base(bd, BattleIndex.Invalid, defenderId, new double[] { damage }, new int[] { criticalType }, attackType, null, defenderHP) - { - var attackerSlots = SetAttacker(); - SetDefender(); - - if (AttackType == 0 && Attacker != null) - AttackType = CaclulateAttackKind(attackerSlots, Attacker.ShipID, Defender.ShipID); - } - - protected override string GetAttackerName() - { - return BattleRes.SupportFleet; - } - - protected override int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID) - { - return -1; - } - - protected override string GetAttackKind() - { - switch (AttackType) - { - case 1: - return ConstantsRes.AirAttack; - case 2: - return ConstantsRes.Shelling; - case 3: - return ConstantsRes.TorpedoAttack; - case 4: - return ConstantsRes.BombingAttack; - default: - return ConstantsRes.Unknown; - } - } - -} - -/// -/// 夜戦における戦闘詳細データを保持します。 -/// -public class BattleNightDetail : BattleDetail -{ - - public bool NightAirAttackFlag { get; protected set; } - - public BattleNightDetail(BattleData bd, BattleIndex attackerId, BattleIndex defenderId, double[] damages, int[] criticalTypes, int attackType, int[] equipmentIDs, bool nightAirAttackFlag, int defenderHP) - : base(bd, attackerId, defenderId, damages, criticalTypes, attackType, equipmentIDs, defenderHP) - { - NightAirAttackFlag = nightAirAttackFlag; - - var attackerSlots = SetAttacker(); - SetDefender(); - - if (AttackType == 0 && Attacker != null) - AttackType = CaclulateAttackKind(attackerSlots, Attacker.ShipID, Defender.ShipID); - } - - protected override int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID) - { - return (int)Calculator.GetNightAttackKind(slots, attackerShipID, defenderShipID, false, NightAirAttackFlag); - } - - protected override string GetAttackKind() - { - return NightAttack.AttackDisplay((NightAttackKind)AttackType); - } -} - -/// -/// 航空戦における戦闘詳細データを保持します。 -/// -public class BattleAirDetail : BattleDayDetail -{ - public int WaveIndex { get; protected set; } - - public BattleAirDetail(BattleData bd, int waveIndex, BattleIndex defenderId, double damage, int criticalType, int attackType, int defenderHP) - : base(bd, BattleIndex.Invalid, defenderId, new double[] { damage }, new int[] { criticalType }, attackType, null, defenderHP) - { - WaveIndex = waveIndex; - } - - protected override string GetAttackerName() - { - if (WaveIndex <= 0) - { - if (DefenderIndex.Side == BattleSides.FriendMain || DefenderIndex.Side == BattleSides.FriendEscort) - return BattleRes.EnemyAirSquadron; - else - return BattleRes.FriendlyAirSquadron; - - } - else - { - return string.Format(BattleRes.AirSquadronWave, WaveIndex); - - } - } - - protected override string GetDefenderName() - { - if (WaveIndex < 0 && DefenderIndex.Side == BattleSides.FriendMain) - return string.Format(BattleRes.Base, DefenderIndex.Index + 1); - - return base.GetDefenderName(); - } - - protected override int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID) - { - return -1; - } - - protected override string GetAttackKind() - { - switch (AttackType) - { - case 1: - return ConstantsRes.TorpedoAttack; - case 2: - return ConstantsRes.BombingAttack; - case 3: - return ConstantsRes.TorpBombingAttack; - default: - return ConstantsRes.Unknown; - } - } - -} - - -/// -/// 友軍艦隊砲撃における戦闘詳細データを保持します。 -/// -public class BattleFriendlyShellingDetail : BattleDetail -{ - - public bool NightAirAttackFlag { get; protected set; } - - public BattleFriendlyShellingDetail(BattleNight bd, BattleIndex attackerId, BattleIndex defenderId, double[] damages, int[] criticalTypes, int attackType, int[] equipmentIDs, bool nightAirAttackFlag, int defenderHP) - : base(bd, attackerId, defenderId, damages, criticalTypes, attackType, equipmentIDs, defenderHP) - { - NightAirAttackFlag = nightAirAttackFlag; - - int[] attackerSlots; - - if (attackerId.IsFriend) - { - Attacker = bd.FriendlySupportInfo.FriendlyMembersInstance[attackerId.Index]; - attackerSlots = bd.FriendlySupportInfo.FriendlySlots[attackerId.Index]; - } - else - { - attackerSlots = SetAttacker(); - } - - if (defenderId.IsFriend) - Defender = bd.FriendlySupportInfo.FriendlyMembersInstance[defenderId.Index]; - else - SetDefender(); - - - if (AttackType == 0 && Attacker != null) - AttackType = CaclulateAttackKind(attackerSlots, Attacker.ShipID, Defender.ShipID); - } - - protected override int CaclulateAttackKind(int[] slots, int attackerShipID, int defenderShipID) - { - return (int)Calculator.GetNightAttackKind(slots, attackerShipID, defenderShipID, false, NightAirAttackFlag); - } - - protected override string GetAttackKind() - { - return NightAttack.AttackDisplay((NightAttackKind)AttackType); - } -} - -/// -/// 友軍艦隊航空攻撃における戦闘詳細データを保持します。 -/// -public class BattleFriendlyAirDetail : BattleAirDetail -{ - public BattleFriendlyAirDetail(BattleData bd, BattleIndex defenderId, double damage, int criticalType, int attackType, int defenderHP) - : base(bd, 0, defenderId, damage, criticalType, attackType, defenderHP) - { - if (defenderId.IsFriend) - Defender = bd.FriendlySupportInfo.FriendlyMembersInstance[defenderId.Index]; - else - SetDefender(); - } - - protected override string GetDefenderName() - { - if (DefenderIndex.IsFriend) - { - return Battle.FriendlySupportInfo.FriendlyMembersInstance[DefenderIndex.Index].NameWithClass + " #" + (DefenderIndex.Index + 1); - } - - return base.GetDefenderName(); - } -} diff --git a/ElectronicObserver/Data/Battle/Detail/BattleDetailDescriptor.cs b/ElectronicObserver/Data/Battle/Detail/BattleDetailDescriptor.cs deleted file mode 100644 index bfdc60a9a..000000000 --- a/ElectronicObserver/Data/Battle/Detail/BattleDetailDescriptor.cs +++ /dev/null @@ -1,751 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using ElectronicObserver.Data.Battle.Phase; -using ElectronicObserver.Resource.Record; -using ElectronicObserver.Utility.Data; -using ElectronicObserver.Window.Wpf; -using ElectronicObserverTypes; -using ElectronicObserverTypes.AntiAir; - -namespace ElectronicObserver.Data.Battle.Detail; - -public static class BattleDetailDescriptor -{ - - public static string GetBattleDetail(BattleManager bm) - { - var sb = new StringBuilder(); - - if (bm.IsPractice) - { - sb.AppendLine(BattleRes.Exercise); - - } - else - { - sb.AppendFormat("{0} ({1}-{2})", bm.Compass.MapInfo.NameEN, bm.Compass.MapAreaID, bm.Compass.MapInfoID); - if (bm.Compass.MapInfo.EventDifficulty > 0) - sb.AppendFormat(" [{0}]", Constants.GetDifficulty(bm.Compass.MapInfo.EventDifficulty)); - sb.Append(ConstantsRes.BattleDetail_Node).Append(bm.Compass.CellId.ToString()); - if (bm.Compass.EventID == 5) - sb.Append(ConstantsRes.BattleDetail_Boss); - sb.AppendLine(); - - var mapinfo = bm.Compass.MapInfo; - if (!mapinfo.IsCleared) - { - if (mapinfo.RequiredDefeatedCount != -1) - { - sb.AppendFormat(BattleRes.ClearProgress, mapinfo.CurrentDefeatedCount, mapinfo.RequiredDefeatedCount) - .AppendLine(); - } - else if (mapinfo.MapHPMax > 0) - { - int current = bm.Compass.MapHPCurrent > 0 ? bm.Compass.MapHPCurrent : mapinfo.MapHPCurrent; - int max = bm.Compass.MapHPMax > 0 ? bm.Compass.MapHPMax : mapinfo.MapHPMax; - sb.AppendFormat("{0}{1}: {2} / {3}", mapinfo.CurrentGaugeIndex > 0 ? "#" + mapinfo.CurrentGaugeIndex + " " : "", mapinfo.GaugeType == 3 ? "TP" : "HP", current, max) - .AppendLine(); - } - } - } - if (bm.Result != null) - { - sb.AppendLine(bm.Result.EnemyFleetName); - } - sb.AppendLine(); - - if (bm.HeavyBaseAirRaids.Count > 0) - { - foreach (BattleBaseAirRaid baseAirRaid in bm.HeavyBaseAirRaids) - { - sb.AppendFormat("◆ {0} ◆\r\n", baseAirRaid.BattleName) - .AppendLine(GetBattleDetail(baseAirRaid)); - } - } - else - { - sb.AppendFormat("◆ {0} ◆\r\n", bm.FirstBattle.BattleName).AppendLine(GetBattleDetail(bm.FirstBattle)); - if (bm.SecondBattle != null) - sb.AppendFormat("◆ {0} ◆\r\n", bm.SecondBattle.BattleName).AppendLine(GetBattleDetail(bm.SecondBattle)); - } - - - if (bm.Result != null) - { - sb.AppendLine(GetBattleResult(bm)); - } - - return sb.ToString(); - } - - - public static string GetBattleDetail(BattleData battle) - { - - var sbmaster = new StringBuilder(); - bool isBaseAirRaid = battle.IsBaseAirRaid; - - - foreach (var phase in battle.GetPhases()) - { - - var sb = new StringBuilder(); - - switch (phase) - { - case PhaseBaseAirRaid p: - - sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", p.Squadrons.Where(sq => sq.EquipmentInstance != null).Select(sq => sq.ToString()).DefaultIfEmpty(BattleRes.Empty))); - - GetBattleDetailPhaseAirBattle(sb, p); - - break; - - case PhaseAirBattle p: - - GetBattleDetailPhaseAirBattle(sb, p); - - break; - - case PhaseBaseAirAttack p: - - foreach (var a in p.AirAttackUnits) - { - sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.AirAttackIndex + 1); - - sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", a.Squadrons.Where(sq => sq.EquipmentInstance != null).Select(sq => sq.ToString()))); - - GetBattleDetailPhaseAirBattle(sb, a); - sb.Append(a.GetBattleDetail()); - } - - break; - - case PhaseJetAirBattle p: - GetBattleDetailPhaseAirBattle(sb, p); - - break; - - case PhaseJetBaseAirAttack p: - - foreach (var a in p.AirAttackUnits) - { - sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.AirAttackIndex + 1); - - sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", a.Squadrons.Where(sq => sq.EquipmentInstance != null).Select(sq => sq.ToString()))); - - GetBattleDetailPhaseAirBattle(sb, a); - sb.Append(a.GetBattleDetail()); - } - - break; - - case PhaseInitial p: - - - if (p.FriendFleetEscort != null) - sb.Append(ConstantsRes.BattleDetail_FriendMainFleet); - else - sb.Append(ConstantsRes.BattleDetail_FriendFleet); - - - void appendFleetInfo(FleetData fleet) - { - sb.Append($" {BattleRes.AirSuperiority} "); - sb.Append(GetRangeString(Calculator.GetAirSuperiority(fleet, false), Calculator.GetAirSuperiority(fleet, true))); - - double truncate2(double value) => Math.Floor(value * 100) / 100; - sb.AppendFormat(BattleRes.Los, - truncate2(Calculator.GetSearchingAbility_New33(fleet, 1)), - truncate2(Calculator.GetSearchingAbility_New33(fleet, 2)), - truncate2(Calculator.GetSearchingAbility_New33(fleet, 3)), - truncate2(Calculator.GetSearchingAbility_New33(fleet, 4))); - } - - if (isBaseAirRaid) - { - sb.AppendLine(); - OutputFriendBase(sb, p.FriendInitialHPs, p.FriendMaxHPs); - } - else - { - appendFleetInfo(p.FriendFleet); - sb.AppendLine(); - OutputFriendData(sb, p.FriendFleet, p.FriendInitialHPs, p.FriendMaxHPs); - } - - if (p.FriendFleetEscort != null) - { - sb.AppendLine(); - sb.Append(ConstantsRes.BattleDetail_FriendEscortFleet); - appendFleetInfo(p.FriendFleetEscort); - sb.AppendLine(); - - OutputFriendData(sb, p.FriendFleetEscort, p.FriendInitialHPsEscort, p.FriendMaxHPsEscort); - } - - - sb.AppendLine(); - - - void appendEnemyFleetInfo(int[] members) - { - int air = 0; - int airbase = 0; - bool indeterminate = false; - for (int i = 0; i < members.Length; i++) - { - var param = RecordManager.Instance.ShipParameter[members[i]]; - if (param == null) continue; - - if (param.DefaultSlot == null || param.Aircraft == null) - { - indeterminate = true; - continue; - } - - for (int s = 0; s < Math.Min(param.DefaultSlot.Length, param.Aircraft.Length); s++) - { - air += Calculator.GetAirSuperiority(param.DefaultSlot[s], param.Aircraft[s]); - if (KCDatabase.Instance.MasterEquipments[param.DefaultSlot[s]]?.IsAircraft ?? false) - airbase += Calculator.GetAirSuperiority(param.DefaultSlot[s], param.Aircraft[s], 0, 0, AirBaseActionKind.Mission); - } - } - sb.AppendFormat(BattleRes.AirBaseAirPower, air, airbase); - if (indeterminate) - sb.Append(BattleRes.ToBeDetermined); - } - - if (p.EnemyMembersEscort != null) - sb.Append(ConstantsRes.BattleDetail_EnemyMainFleet); - else - sb.Append(ConstantsRes.BattleDetail_EnemyFleet); - - appendEnemyFleetInfo(p.EnemyMembers); - - if (p.IsBossDamaged) - sb.Append(BattleRes.BossDebuffed); - sb.AppendLine(); - - OutputEnemyData(sb, p.EnemyMembersInstance, p.EnemyLevels, p.EnemyInitialHPs, p.EnemyMaxHPs, p.EnemySlotsInstance, p.EnemyParameters); - - - if (p.EnemyMembersEscort != null) - { - sb.AppendLine(); - sb.AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); - - appendEnemyFleetInfo(p.EnemyMembersEscort); - sb.AppendLine(); - - OutputEnemyData(sb, p.EnemyMembersEscortInstance, p.EnemyLevelsEscort, p.EnemyInitialHPsEscort, p.EnemyMaxHPsEscort, p.EnemySlotsEscortInstance, p.EnemyParametersEscort); - } - - sb.AppendLine(); - - if (battle.GetPhases().Where(ph => ph is PhaseBaseAirAttack || ph is PhaseBaseAirRaid).Any(ph => ph != null && ph.IsAvailable)) - { - sb.AppendLine(ConstantsRes.BattleDetail_AirBase); - GetBattleDetailBaseAirCorps(sb, KCDatabase.Instance.Battle.Compass.MapAreaID); // :( - sb.AppendLine(); - } - - if (p.RationIndexes.Length > 0) - { - sb.AppendLine($"〈{BattleRes.CombatRation}〉"); - foreach (var index in p.RationIndexes) - { - var ship = p.GetFriendShip(index); - - if (ship != null) - { - sb.AppendFormat(" {0} #{1}\r\n", ship.NameWithLevel, index + 1); - } - } - sb.AppendLine(); - } - - break; - - case PhaseNightInitial p: - - { - var eq = KCDatabase.Instance.MasterEquipments[p.TouchAircraftFriend]; - if (eq != null) - { - sb.Append(ConstantsRes.BattleDetail_FriendlyNightContact).AppendLine(eq.NameEN); - } - eq = KCDatabase.Instance.MasterEquipments[p.TouchAircraftEnemy]; - if (eq != null) - { - sb.Append(ConstantsRes.BattleDetail_EnemyNightContact).AppendLine(eq.NameEN); - } - } - - { - int searchlightIndex = p.SearchlightIndexFriend; - if (searchlightIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_FriendlySearchlight + "\r\n", p.FriendFleet.MembersInstance[searchlightIndex].Name, searchlightIndex + 1); - } - searchlightIndex = p.SearchlightIndexEnemy; - if (searchlightIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_EnemySearchlight + "\r\n", p.EnemyMembersInstance[searchlightIndex].NameWithClass, searchlightIndex + 1); - } - } - - if (p.FlareIndexFriend != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", p.FlareFriendInstance.NameWithLevel, p.FlareIndexFriend + 1); - } - if (p.FlareIndexEnemy != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", p.FlareEnemyInstance.NameWithClass, p.FlareIndexEnemy + 1); - } - - sb.AppendLine(); - break; - - - case PhaseSearching p: - sb.Append($"{BattleRes.Formation}: ").Append(Constants.GetFormation(p.FormationFriend)); - sb.Append($" / {BattleRes.EnemyFormation}: ").AppendLine(Constants.GetFormation(p.FormationEnemy)); - sb.Append($"{BattleRes.Engagement}: ").AppendLine(Constants.GetEngagementForm(p.EngagementForm)); - sb.Append($"{BattleRes.Contact}: ").Append(Constants.GetSearchingResult(p.SearchingFriend)); - sb.Append($" / {BattleRes.EnemyContact}: ").AppendLine(Constants.GetSearchingResult(p.SearchingEnemy)); - - if (p.SmokeCount > 0) - { - sb.AppendLine($"{BattleRes.SmokeScreen} x{p.SmokeCount}"); - } - - sb.AppendLine(); - - break; - - case PhaseSupport p: - if (p.IsAvailable) - { - sb.AppendLine($"〈{BattleRes.SupportFleet}〉"); - OutputSupportData(sb, p.SupportFleet); - sb.AppendLine(); - } - break; - - case PhaseFriendlySupportInfo p: - if (p.IsAvailable) - { - OutputFriendlySupportData(sb, p); - sb.AppendLine(); - } - break; - - case PhaseFriendlyShelling p: - if (p.IsAvailable) - { - { - int searchlightIndex = p.SearchlightIndexFriend; - if (searchlightIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_FriendlySearchlight + "\r\n", p.SearchlightFriendInstance.NameWithClass, searchlightIndex + 1); - } - searchlightIndex = p.SearchlightIndexEnemy; - if (searchlightIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_EnemySearchlight + "\r\n", p.SearchlightEnemyInstance.NameWithClass, searchlightIndex + 1); - } - } - - { - int flareIndex = p.FlareIndexFriend; - if (flareIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", p.FlareFriendInstance.NameWithClass, flareIndex + 1); - } - flareIndex = p.FlareIndexEnemy; - if (flareIndex != -1) - { - sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", p.FlareEnemyInstance.NameWithClass, flareIndex + 1); - } - } - - sb.AppendLine(); - } - break; - - case PhaseFriendlyAirBattle p: - - GetBattleDetailPhaseAirBattle(sb, p); - - break; - } - - - if (!(phase is PhaseBaseAirAttack || phase is PhaseJetBaseAirAttack)) // 通常出力と重複するため - sb.Append(phase.GetBattleDetail()); - - if (sb.Length > 0) - { - sbmaster.AppendFormat("== {0} ==\r\n", phase.Title).Append(sb); - } - } - - - { - sbmaster.AppendLine(ConstantsRes.BattleDetail_BattleEnd); - - var friend = battle.Initial.FriendFleet; - var friendescort = battle.Initial.FriendFleetEscort; - var enemy = battle.Initial.EnemyMembersInstance; - var enemyescort = battle.Initial.EnemyMembersEscortInstance; - - if (friendescort != null) - sbmaster.AppendLine(ConstantsRes.BattleDetail_FriendMainFleet); - else - sbmaster.AppendLine(ConstantsRes.BattleDetail_FriendFleet); - - if (isBaseAirRaid) - { - - for (int i = 0; i < 6; i++) - { - if (battle.Initial.FriendMaxHPs[i] <= 0) - continue; - - OutputResultData(sbmaster, i, string.Format(BattleRes.Base, i + 1), - battle.Initial.FriendInitialHPs[i], battle.ResultHPs[i], battle.Initial.FriendMaxHPs[i]); - } - - } - else - { - for (int i = 0; i < friend.Members.Count(); i++) - { - var ship = friend.MembersInstance[i]; - if (ship == null) - continue; - - OutputResultData(sbmaster, i, ship.Name, - battle.Initial.FriendInitialHPs[i], battle.ResultHPs[i], battle.Initial.FriendMaxHPs[i]); - } - } - - if (friendescort != null) - { - sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_FriendEscortFleet); - - for (int i = 0; i < friendescort.Members.Count(); i++) - { - var ship = friendescort.MembersInstance[i]; - if (ship == null) - continue; - - OutputResultData(sbmaster, i + 6, ship.Name, - battle.Initial.FriendInitialHPsEscort[i], battle.ResultHPs[i + 6], battle.Initial.FriendMaxHPsEscort[i]); - } - - } - - - sbmaster.AppendLine(); - if (enemyescort != null) - sbmaster.AppendLine(ConstantsRes.BattleDetail_EnemyMainFleet); - else - sbmaster.AppendLine(ConstantsRes.BattleDetail_EnemyFleet); - - for (int i = 0; i < enemy.Length; i++) - { - var ship = enemy[i]; - if (ship == null) - continue; - - OutputResultData(sbmaster, i, - ship.NameWithClass, - battle.Initial.EnemyInitialHPs[i], battle.ResultHPs[i + 12], battle.Initial.EnemyMaxHPs[i]); - } - - if (enemyescort != null) - { - sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); - - for (int i = 0; i < enemyescort.Length; i++) - { - var ship = enemyescort[i]; - if (ship == null) - continue; - - OutputResultData(sbmaster, i + 6, ship.NameWithClass, - battle.Initial.EnemyInitialHPsEscort[i], battle.ResultHPs[i + 18], battle.Initial.EnemyMaxHPsEscort[i]); - } - } - - sbmaster.AppendLine(); - } - - return sbmaster.ToString(); - } - - private static string GetRangeString(int min, int max) => min != max ? $"{min} ~ {max}" : min.ToString(); - - private static void GetBattleDetailBaseAirCorps(StringBuilder sb, int mapAreaID) - { - foreach (var corps in KCDatabase.Instance.BaseAirCorps.Values.Where(corps => corps.MapAreaID == mapAreaID)) - { - sb.AppendFormat("{0} [{1}] " + BattleRes.AirSuperiority + " {2}\r\n {3}\r\n", - corps.Name, Constants.GetBaseAirCorpsActionKind(corps.ActionKind), - GetRangeString(Calculator.GetAirSuperiority(corps, false), Calculator.GetAirSuperiority(corps, true)), - string.Join(", ", corps.Squadrons.Values - .Where(sq => sq.State == 1 && sq.EquipmentInstance != null) - .Select(sq => sq.EquipmentInstance.NameWithLevel))); - } - } - - private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseAirBattleBase p) - { - - if (p.IsStage1Available) - { - sb.Append("Stage 1: ").AppendLine(Constants.GetAirSuperiority(p.AirSuperiority)); - sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", - p.AircraftLostStage1Friend, p.AircraftTotalStage1Friend, - p.AircraftLostStage1Enemy, p.AircraftTotalStage1Enemy); - if (p.TouchAircraftFriend > 0) - sb.AppendFormat($" {BattleRes.Contact}: {{0}}\r\n", KCDatabase.Instance.MasterEquipments[p.TouchAircraftFriend].NameEN); - if (p.TouchAircraftEnemy > 0) - sb.AppendFormat($" {BattleRes.EnemyContact}: {{0}}\r\n", KCDatabase.Instance.MasterEquipments[p.TouchAircraftEnemy].NameEN); - } - if (p.IsStage2Available) - { - sb.Append("Stage 2: "); - if (p.IsAACutinAvailable) - { - sb.AppendFormat(BattleRes.AaciType, - p.AACutInShipName, - AntiAirCutIn.FromId(p.AACutInKind).EquipmentConditionsSingleLineDisplay(), - p.AACutInKind); - } - sb.AppendLine(); - sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", - p.AircraftLostStage2Friend, p.AircraftTotalStage2Friend, - p.AircraftLostStage2Enemy, p.AircraftTotalStage2Enemy); - } - - if (p.IsStage1Available || p.IsStage2Available) - sb.AppendLine(); - } - - - private static void OutputFriendData(StringBuilder sb, FleetData fleet, int[] initialHPs, int[] maxHPs) - { - - for (int i = 0; i < fleet.MembersInstance.Count; i++) - { - var ship = fleet.MembersInstance[i]; - - if (ship == null) - continue; - - sb.AppendFormat($"#{{0}}: {{1}} {{2}} " + - $"HP: {{3}} / {{4}} - " + - $"{GeneralRes.Firepower}:{{5}}, " + - $"{GeneralRes.Torpedo}:{{6}}, " + - $"{GeneralRes.AntiAir}:{{7}}, " + - $"{GeneralRes.Armor}:{{8}}{{9}}\r\n", - i + 1, - ship.MasterShip.ShipTypeName, ship.NameWithLevel, - initialHPs[i], maxHPs[i], - ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase, - fleet.EscapedShipList.Contains(ship.MasterID) ? $" ({BattleRes.Escaped})" : ""); - - sb.Append(" "); - sb.AppendLine(string.Join(", ", ship.AllSlotInstance.Zip( - ship.ExpansionSlot > 0 ? ship.Aircraft.Concat(new[] { 0 }) : ship.Aircraft, - (eq, aircraft) => eq == null ? null : ((eq.MasterEquipment.IsAircraft ? $"[{aircraft}] " : "") + eq.NameWithLevel) - ).Where(str => str != null))); - } - } - - private static void OutputFriendBase(StringBuilder sb, int[] initialHPs, int[] maxHPs) - { - - for (int i = 0; i < initialHPs.Length; i++) - { - if (maxHPs[i] <= 0) - continue; - - sb.AppendFormat(BattleRes.OutputFriendBase + "\r\n\r\n", - i + 1, - i + 1, - initialHPs[i], maxHPs[i]); - } - - } - - public static void OutputSupportData(StringBuilder sb, FleetData fleet) - { - - for (int i = 0; i < fleet.MembersInstance.Count; i++) - { - var ship = fleet.MembersInstance[i]; - - if (ship == null) - continue; - - sb.AppendFormat($"#{{0}}: {{1}} {{2}} - " + - $"{{3}} {GeneralRes.Firepower}, " + - $"{{4}} {GeneralRes.Torpedo}, " + - $"{{5}} {GeneralRes.AntiAir}, " + - $"{{6}} {GeneralRes.Armor}" + - $"\r\n", - i + 1, - ship.MasterShip.ShipTypeName, ship.NameWithLevel, - ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase); - - sb.Append(" "); - sb.AppendLine(string.Join(", ", ship.AllSlotInstance.Where(eq => eq != null))); - } - - } - - private static void OutputFriendlySupportData(StringBuilder sb, PhaseFriendlySupportInfo p) - { - - for (int i = 0; i < p.FriendlyMembersInstance.Length; i++) - { - var ship = p.FriendlyMembersInstance[i]; - - if (ship == null) - continue; - - sb.AppendFormat($"#{{0}}: {{1}} {{2}} " + - $"Lv. {{3}} " + - $"HP: {{4}} / {{5}} - " + - $"{GeneralRes.Firepower} {{6}}, " + - $"{GeneralRes.Torpedo} {{7}}, " + - $"{GeneralRes.AntiAir} {{8}}, " + - $"{GeneralRes.Armor} {{9}}" + - $"\r\n", - i + 1, - ship.ShipTypeName, p.FriendlyMembersInstance[i].NameWithClass, p.FriendlyLevels[i], - p.FriendlyInitialHPs[i], p.FriendlyMaxHPs[i], - p.FriendlyParameters[i][0], p.FriendlyParameters[i][1], p.FriendlyParameters[i][2], p.FriendlyParameters[i][3]); - - sb.Append(" "); - sb.AppendLine(string.Join(", ", p.FriendlySlots[i] - .Concat(new[] { p.FriendlyExpansionSlots?[i] ?? -1 }) - .Select(id => KCDatabase.Instance.MasterEquipments[id]) - .Where(eq => eq != null) - .Select(eq => eq.NameEN))); - } - } - - private static void OutputEnemyData(StringBuilder sb, IShipDataMaster[] members, int[] levels, int[] initialHPs, int[] maxHPs, IEquipmentDataMaster[][] slots, int[][] parameters) - { - - for (int i = 0; i < members.Length; i++) - { - if (members[i] == null) - continue; - - sb.AppendFormat("#{0}: ID:{1} {2} {3} Lv. {4} HP: {5} / {6}", - i + 1, - members[i].ShipID, - members[i].ShipTypeName, members[i].NameWithClass, - levels[i], - initialHPs[i], maxHPs[i]); - - if (parameters != null) - { - sb.AppendFormat($" - " + - $"{GeneralRes.Firepower}:{{0}}, " + - $"{GeneralRes.Torpedo}:{{1}}, " + - $"{GeneralRes.AntiAir}:{{2}}, " + - $"{GeneralRes.Armor}:{{3}}", - parameters[i][0], parameters[i][1], parameters[i][2], parameters[i][3]); - } - - sb.AppendLine().Append(" "); - sb.AppendLine(string.Join(", ", slots[i].Where(eq => eq != null))); - } - } - - - private static void OutputResultData(StringBuilder sb, int index, string name, int initialHP, int resultHP, int maxHP) - { - sb.AppendFormat("#{0}: {1} HP: ({2} → {3})/{4} ({5})\r\n", - index + 1, name, - Math.Max(initialHP, 0), - Math.Max(resultHP, 0), - Math.Max(maxHP, 0), - resultHP - initialHP); - } - - - private static string GetBattleResult(BattleManager bm) - { - var result = bm.Result; - - var sb = new StringBuilder(); - - - sb.AppendLine(ConstantsRes.BattleDetail_Result); - sb.AppendFormat(ConstantsRes.BattleDetail_ResultRank + "\r\n", result.Rank); - - if (bm.IsCombinedBattle) - { - sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPMain + "\r\n", - result.MVPIndex == -1 ? "(なし)" : bm.FirstBattle.Initial.FriendFleet.MembersInstance[result.MVPIndex - 1].NameWithLevel); - sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPEscort + "\r\n", - result.MVPIndexCombined == -1 ? "(なし)" : bm.FirstBattle.Initial.FriendFleetEscort.MembersInstance[result.MVPIndexCombined - 1].NameWithLevel); - - } - else - { - sb.AppendFormat("MVP: {0}\r\n", - result.MVPIndex == -1 ? "(なし)" : bm.FirstBattle.Initial.FriendFleet.MembersInstance[result.MVPIndex - 1].NameWithLevel); - } - - sb.AppendFormat(ConstantsRes.BattleDetail_AdmiralExp + "\r\n", result.AdmiralExp); - sb.AppendFormat(ConstantsRes.BattleDetail_ShipExp + "\r\n", result.BaseExp); - - if (!bm.IsPractice) - { - sb.AppendLine().AppendLine(ConstantsRes.BattleDetail_Drop); - - - int length = sb.Length; - - var ship = KCDatabase.Instance.MasterShips[result.DroppedShipID]; - if (ship != null) - { - sb.AppendFormat(" {0} {1}\r\n", ship.ShipTypeName, ship.NameWithClass); - } - - var eq = KCDatabase.Instance.MasterEquipments[result.DroppedEquipmentID]; - if (eq != null) - { - sb.AppendFormat(" {0} {1}\r\n", eq.CategoryTypeInstance.NameEN, eq.NameEN); - } - - var item = KCDatabase.Instance.MasterUseItems[result.DroppedItemID]; - if (item != null) - { - sb.Append(" ").AppendLine(item.NameTranslated); - } - - if (length == sb.Length) - { - sb.AppendLine(" (なし)"); - } - } - - - return sb.ToString(); - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseAirBattle.cs b/ElectronicObserver/Data/Battle/Phase/PhaseAirBattle.cs deleted file mode 100644 index 44d6aef94..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseAirBattle.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 航空戦フェーズの処理を行います。 -/// -public class PhaseAirBattle : PhaseAirBattleBase -{ - - public PhaseAirBattle(BattleData data, string title, string suffix = "") - : base(data, title) - { - - AirBattleData = RawData.IsDefined("api_kouku" + suffix) ? RawData["api_kouku" + suffix] : null; - StageFlag = RawData.IsDefined("api_stage_flag" + suffix) ? (int[])RawData["api_stage_flag" + suffix] : null; - - LaunchedShipIndexFriend = GetLaunchedShipIndex(0); - LaunchedShipIndexEnemy = GetLaunchedShipIndex(1); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) return; - - CalculateAttack(0, hps); - CalculateAttackDamage(damages); - } - - - - /// - /// 航空戦での与ダメージを推測します。 - /// - /// 与ダメージリスト。 - private void CalculateAttackDamage(int[] damages) - { - // 敵はめんどくさすぎるので省略 - // 仮想火力を求め、それに従って合計ダメージを分配 - - var firepower = new int[12]; - var launchedIndex = LaunchedShipIndexFriend; - - foreach (int i in launchedIndex) - { - var ship = Battle.Initial.GetFriendShip(i); - - if (ship == null) - continue; - - var slots = ship.SlotInstanceMaster; - var aircrafts = ship.Aircraft; - for (int s = 0; s < slots.Count; s++) - { - - if (slots[s] == null) - continue; - - switch (slots[s].CategoryType) - { - // 通常の爆撃機系 - case EquipmentTypes.CarrierBasedBomber: - case EquipmentTypes.SeaplaneBomber: - firepower[i] += (int)(1.0 * (slots[s].Bomber * Math.Sqrt(aircrafts[s]) + 25)); - break; - - // 噴式爆撃機 - case EquipmentTypes.JetBomber: - firepower[i] += (int)(1.0 / Math.Sqrt(2) * (slots[s].Bomber * Math.Sqrt(aircrafts[s]) + 25)); - break; - - // 通常の攻撃機系 (80%と150%はランダムのため係数は平均値) - case EquipmentTypes.CarrierBasedTorpedo: - firepower[i] += (int)(1.15 * (slots[s].Torpedo * Math.Sqrt(aircrafts[s]) + 25)); - break; - - // 噴式攻撃機(いる?) - case EquipmentTypes.JetTorpedo: - firepower[i] += (int)(1.15 / Math.Sqrt(2) * (slots[s].Torpedo * Math.Sqrt(aircrafts[s]) + 25)); - break; - } - } - } - - int totalFirepower = firepower.Sum(); - int totalDamage = Damages.Select(dmg => (int)dmg).Skip(12).Take(12).Sum(); - - for (int i = 0; i < firepower.Length; i++) - { - damages[i] += (int)Math.Round((double)totalDamage * firepower[i] / Math.Max(totalFirepower, 1)); - } - } - - protected override IEnumerable SearchBattleDetails(int index) - { - return BattleDetails.Where(d => d.DefenderIndex == index); - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseAirBattleBase.cs b/ElectronicObserver/Data/Battle/Phase/PhaseAirBattleBase.cs deleted file mode 100644 index 0c14dd07b..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseAirBattleBase.cs +++ /dev/null @@ -1,272 +0,0 @@ -using System; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 航空戦フェーズ処理の基底となるクラスです。 -/// -public abstract class PhaseAirBattleBase : PhaseBase -{ - - public PhaseAirBattleBase(BattleData data, string title) - : base(data, title) - { - - } - - public override bool IsAvailable => StageFlag != null && StageFlag.Any(i => i != 0); - - - - /// - /// 被ダメージ処理を行います。 - /// - /// (基地航空隊の場合)現在の攻撃ウェーブのインデックス。それ以外の場合は 0 - /// 現在のHPリスト。 - protected void CalculateAttack(int waveIndex, int[] hps) - { - for (int i = 0; i < hps.Length; i++) - { - - int attackType = (TorpedoFlags[i] > 0 ? 1 : 0) | (BomberFlags[i] > 0 ? 2 : 0); - if (attackType > 0) - { - - // 航空戦は miss/hit=0, critical=1 のため +1 する(通常は miss=0, hit=1, critical=2) - BattleDetails.Add(new BattleAirDetail(Battle, waveIndex, new BattleIndex(i, Battle.IsFriendCombined, Battle.IsEnemyCombined), Damages[i], Criticals[i] + 1, attackType, hps[i])); - AddDamage(hps, i, (int)Damages[i]); - } - } - } - - - - /// - /// 各 Stage が存在するか - /// - public int[] StageFlag { get; protected set; } - - /// - /// 航空戦の生データ - /// - public dynamic AirBattleData { get; protected set; } - - - /// - /// 航空機を発艦させた自軍艦船のインデックス 値は[0-11] - /// - public int[] LaunchedShipIndexFriend { get; protected set; } - - /// - /// 航空機を発艦させた敵軍艦船のインデックス 値は[0-11] - /// - public int[] LaunchedShipIndexEnemy { get; protected set; } - - - /// - /// 航空機を発艦させた艦船のインデックスを取得します。 - /// - /// 取得する配列のインデックス。基本的に 0=自軍, 1=敵軍 - protected int[] GetLaunchedShipIndex(int index) - { - if (AirBattleData == null) - return null; - - if (!AirBattleData.api_plane_from()) - return new int[0]; - - dynamic data = AirBattleData.api_plane_from; - - if (data == null || !data.IsArray) - return new int[0]; - - var planes = (dynamic[]?)data; - if (index < planes?.Length) - { - var plane = (int[])planes[index]; - - if (plane == null) - return new int[0]; - - return plane.Where(i => i > 0).Select(i => i - 1).ToArray(); - } - - return new int[0]; - } - - - // stage 1 - - /// - /// Stage1(空対空戦闘)が存在するか - /// - public bool IsStage1Available => StageFlag != null && StageFlag[0] != 0 && AirBattleData.api_stage1() && AirBattleData.api_stage1 != null; - - /// - /// 自軍Stage1参加機数 - /// - public int AircraftTotalStage1Friend => (int)AirBattleData.api_stage1.api_f_count; - - /// - /// 敵軍Stage1参加機数 - /// - public int AircraftTotalStage1Enemy => (int)AirBattleData.api_stage1.api_e_count; - - /// - /// 自軍Stage1撃墜機数 - /// - public int AircraftLostStage1Friend => (int)AirBattleData.api_stage1.api_f_lostcount; - - /// - /// 敵軍Stage1撃墜機数 - /// - public int AircraftLostStage1Enemy => (int)AirBattleData.api_stage1.api_e_lostcount; - - /// - /// 制空権 - /// - public int AirSuperiority => !AirBattleData.api_stage1.api_disp_seiku() ? -1 : (int)AirBattleData.api_stage1.api_disp_seiku; - - /// - /// 自軍触接機ID - /// - public int TouchAircraftFriend => !AirBattleData.api_stage1.api_touch_plane() ? -1 : (int)AirBattleData.api_stage1.api_touch_plane[0]; - - /// - /// 敵軍触接機ID - /// - public int TouchAircraftEnemy => !AirBattleData.api_stage1.api_touch_plane() ? -1 : (int)AirBattleData.api_stage1.api_touch_plane[1]; - - - // stage 2 - - /// - /// Stage2(艦対空戦闘)が存在するか - /// - public bool IsStage2Available => StageFlag != null && StageFlag[1] != 0 && AirBattleData.api_stage2() && AirBattleData.api_stage2 != null; - - /// - /// 自軍Stage2参加機数 - /// - public int AircraftTotalStage2Friend => (int)AirBattleData.api_stage2.api_f_count; - - /// - /// 敵軍Stage2参加機数 - /// - public int AircraftTotalStage2Enemy => (int)AirBattleData.api_stage2.api_e_count; - - /// - /// 自軍Stage2撃墜機数 - /// - public int AircraftLostStage2Friend => (int)AirBattleData.api_stage2.api_f_lostcount; - - /// - /// 敵軍Stage2撃墜機数 - /// - public int AircraftLostStage2Enemy => (int)AirBattleData.api_stage2.api_e_lostcount; - - - /// - /// 対空カットインが発動したか - /// - public bool IsAACutinAvailable => AirBattleData.api_stage2.api_air_fire(); - - /// - /// 対空カットイン発動艦番号 - /// - public int AACutInIndex => (int)AirBattleData.api_stage2.api_air_fire.api_idx; - - /// - /// 対空カットイン発動艦 - /// - public IShipData AACutInShip => Battle.Initial.GetFriendShip(AACutInIndex); - - /// - /// 対空カットイン発動艦の名前 - /// - public virtual string AACutInShipName => AACutInShip.NameWithLevel; - - /// - /// 対空カットイン種別 - /// - public int AACutInKind => (int)AirBattleData.api_stage2.api_air_fire.api_kind; - - - // stage 3 - - /// - /// Stage3(航空攻撃)が存在するか - /// - public bool IsStage3Available => StageFlag != null && StageFlag[2] != 0 && AirBattleData.api_stage3() && AirBattleData.api_stage3 != null; - - /// - /// Stage3(航空攻撃)(対随伴艦隊)が存在するか - /// - public bool IsStage3CombinedAvailable => StageFlag != null && StageFlag[2] != 0 && AirBattleData.api_stage3_combined() && AirBattleData.api_stage3_combined != null; - - - protected T[] ConcatStage3Array(string friendName, string enemyName) where T : struct, IComparable - { - - T[] ret = new T[24]; - - void SetArray(string stage3Name, string sideName, int retIndex) - { - if (!AirBattleData[stage3Name].IsDefined(sideName)) - return; - - var ar = (dynamic[])AirBattleData[stage3Name][sideName]; - if (ar == null) - return; - - for (int i = 0; i < ar.Length; i++) - { - var value = (T?)ar[i] ?? default(T); - - // Max(value, 0) - if (value.CompareTo(default(T)) < 0) - value = default(T); - - ret[retIndex + i] = value; - } - } - - - if (IsStage3Available) - { - SetArray("api_stage3", friendName, 0); - SetArray("api_stage3", enemyName, 12); - } - if (IsStage3CombinedAvailable) - { - SetArray("api_stage3_combined", friendName, 6); - SetArray("api_stage3_combined", enemyName, 18); - } - - return ret; - } - - - /// - /// 被雷撃フラグ - /// - public int[] TorpedoFlags { get; protected set; } - - /// - /// 被爆撃フラグ - /// - public int[] BomberFlags { get; protected set; } - - /// - /// 各艦のクリティカルフラグ - /// - public int[] Criticals { get; protected set; } - - /// - /// 各艦の被ダメージ - /// - public double[] Damages { get; protected set; } -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseBase.cs b/ElectronicObserver/Data/Battle/Phase/PhaseBase.cs deleted file mode 100644 index b42b8b425..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseBase.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 戦闘フェーズの基底クラスです。 -/// -public abstract class PhaseBase -{ - protected BattleData Battle; - public List BattleDetails { get; protected set; } - public readonly string Title; - - - private string TranslatedPhaseTitle(string title) => title switch - { - "噴式基地航空隊攻撃" => BattleRes.BattlePhaseLandBasedJet, - "噴式航空戦" => BattleRes.BattlePhaseJet, - "基地航空隊攻撃" => BattleRes.BattlePhaseLandBasedAir, - "防空戦" => BattleRes.BattlePhaseAirBaseRaid, - "航空戦" => BattleRes.BattlePhaseAirBattle, - "空襲戦" => BattleRes.BattlePhaseAirRaid, - "第一次航空戦" => BattleRes.BattlePhaseAirAttackFirst, - "第二次航空戦" => BattleRes.BattlePhaseAirAttackSecond, - "支援攻撃" => BattleRes.BattlePhaseSupportExpedition, - "先制対潜" => BattleRes.BattlePhaseOpeningAsw, - "先制雷撃" => BattleRes.BattlePhaseOpeningTorpedo, - "第一次砲撃戦" => BattleRes.BattlePhaseShellingFirst, - "第二次砲撃戦" => BattleRes.BattlePhaseShellingSecond, - "第三次砲撃戦" => BattleRes.BattlePhaseShellingThird, - "雷撃戦" => BattleRes.BattlePhaseClosingTorpedo, - "夜戦" => BattleRes.BattlePhaseNightBattle, - "第一次夜戦" => BattleRes.BattlePhaseNightBattleFirst, - "第二次夜戦" => BattleRes.BattlePhaseNightBattleSecond, - "夜間支援攻撃" => BattleRes.BattlePhaseNightSupportExpedition, - - _ => title, - }; - - protected PhaseBase(BattleData battle, string title) - { - Battle = battle; - BattleDetails = new List(); - Title = TranslatedPhaseTitle(title); - } - - - protected dynamic RawData => Battle.RawData; - - - protected static bool IsIndexFriend(int index) => 0 <= index && index < 12; - protected static bool IsIndexEnemy(int index) => 12 <= index && index < 24; - - - /// - /// 被ダメージ処理を行います。 - /// - /// 各艦のHPリスト。 - /// ダメージを受ける艦のインデックス。 - /// ダメージ。 - protected void AddDamage(int[] hps, int index, int damage) - { - - hps[index] -= Math.Max(damage, 0); - - // 自軍艦の撃沈が発生した場合(ダメコン処理) - if (hps[index] <= 0 && IsIndexFriend(index) && !Battle.IsPractice) - { - var ship = Battle.Initial.GetFriendShip(index); - if (ship == null) - return; - - int id = ship.DamageControlID; - - if (id == 42) - hps[index] = (int)(ship.HPMax * 0.2); - - else if (id == 43) - hps[index] = ship.HPMax; - - } - } - - - protected virtual IEnumerable SearchBattleDetails(int index) - { - return BattleDetails.Where(d => d.AttackerIndex == index || d.DefenderIndex == index); - } - public virtual string GetBattleDetail(int index) - { - IEnumerable list; - if (index == -1) - list = BattleDetails; - else - list = SearchBattleDetails(index); - - if (list.Any()) - { - return string.Join("\r\n", list) + "\r\n"; - } - else return null; - } - public virtual string GetBattleDetail() { return GetBattleDetail(-1); } - - - public override string ToString() => string.Join(" / \r\n", BattleDetails); - - - - /// - /// データが有効かどうかを示します。 - /// - public abstract bool IsAvailable { get; } - - /// - /// 戦闘をエミュレートします。 - /// - /// 各艦のHPリスト。 - /// 各艦の与ダメージリスト。 - public abstract void EmulateBattle(int[] hps, int[] damages); - - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirAttack.cs b/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirAttack.cs deleted file mode 100644 index 0e5b25741..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirAttack.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 基地航空隊攻撃フェーズの処理を行います。 -/// -public class PhaseBaseAirAttack : PhaseBase -{ - - - /// - /// 基地航空隊攻撃フェーズの、個々の攻撃フェーズの処理を行います。 - /// - public class PhaseBaseAirAttackUnit : PhaseAirBattleBase - { - - - public PhaseBaseAirAttackUnit(BattleData data, string title, int index) - : base(data, title) - { - - AirAttackIndex = index; - AirBattleData = data.RawData.api_air_base_attack[index]; - StageFlag = AirBattleData.api_stage_flag() ? (int[])AirBattleData.api_stage_flag : null; - - LaunchedShipIndexEnemy = GetLaunchedShipIndex(0); - - _squadrons = GetSquadrons().ToArray(); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) return; - - CalculateAttack(AirAttackIndex + 1, hps); - } - - - /// - /// 攻撃ID (第n波, 0から始まる) - /// - public int AirAttackIndex { get; private set; } - - /// - /// 航空隊ID - /// - public int AirUnitID => (int)AirBattleData.api_base_id; - - - - private BattleBaseAirCorpsSquadron[] _squadrons; - /// - /// 参加した航空中隊データ - /// - public ReadOnlyCollection Squadrons => Array.AsReadOnly(_squadrons); - - private IEnumerable GetSquadrons() - { - foreach (dynamic d in AirBattleData.api_squadron_plane) - yield return new BattleBaseAirCorpsSquadron(d); - } - - } - - - - public PhaseBaseAirAttack(BattleData data, string title) - : base(data, title) - { - - AirAttackUnits = new List(); - - if (!IsAvailable) - return; - - - int i = 0; - foreach (var unit in RawData.api_air_base_attack) - { - AirAttackUnits.Add(new PhaseBaseAirAttackUnit(data, title, i)); - i++; - } - - } - - - /// - /// 個々の攻撃フェーズのデータ - /// - public List AirAttackUnits { get; private set; } - - - - public override bool IsAvailable => RawData.api_air_base_attack(); - - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) - return; - - foreach (var a in AirAttackUnits) - { - - a.EmulateBattle(hps, damages); - } - } - - - protected override IEnumerable SearchBattleDetails(int index) - { - return AirAttackUnits.SelectMany(p => p.BattleDetails).Where(d => d.DefenderIndex == index); - } - -} - - -/// -/// 戦闘に参加した基地航空隊中隊のデータ -/// -public class BattleBaseAirCorpsSquadron -{ - public int EquipmentID { get; private set; } - public int AircraftCount { get; private set; } - public IEquipmentDataMaster EquipmentInstance => KCDatabase.Instance.MasterEquipments[EquipmentID]; - - public BattleBaseAirCorpsSquadron(dynamic data) - { - EquipmentID = (int)data.api_mst_id; - AircraftCount = (int)data.api_count; - } - - public override string ToString() => $"{EquipmentInstance?.NameEN ?? "Unknown Plane"} x {AircraftCount}"; - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirRaid.cs deleted file mode 100644 index b4c22c31a..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseBaseAirRaid.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using DynaJson; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 基地空襲戦フェーズ -/// -public class PhaseBaseAirRaid : PhaseAirBattleBase -{ - - private BattleBaseAirCorpsSquadron[] _squadrons; - /// - /// 参加した航空中隊データ - /// - public ReadOnlyCollection Squadrons => Array.AsReadOnly(_squadrons); - - private IEnumerable GetSquadrons() - { - if (AirBattleData.api_map_squadron_plane == null) - yield break; - - foreach (KeyValuePair p in AirBattleData.api_map_squadron_plane) - { - if (!(p.Value is JsonObject)) - continue; - if (!p.Value.IsArray) - continue; - - foreach (dynamic e in p.Value) - yield return new BattleBaseAirCorpsSquadron(e); - } - } - - - public PhaseBaseAirRaid(BattleData data, string title) - : base(data, title) - { - - AirBattleData = data.RawData.api_air_base_attack; - StageFlag = AirBattleData.api_stage_flag() ? (int[])AirBattleData.api_stage_flag : null; - - LaunchedShipIndexFriend = GetLaunchedShipIndex(0); - LaunchedShipIndexEnemy = GetLaunchedShipIndex(1); - - _squadrons = GetSquadrons().ToArray(); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) return; - - CalculateAttack(-1, hps); - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyAirBattle.cs b/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyAirBattle.cs deleted file mode 100644 index d267d685c..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyAirBattle.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 昼戦における友軍艦隊航空攻撃フェーズの処理を行います。 -/// -public class PhaseFriendlyAirBattle : PhaseAirBattleBase -{ - public PhaseFriendlyAirBattle(BattleData battle, string title) - : base(battle, title) - { - if (!IsAvailable) - return; - - AirBattleData = RawData.api_friendly_kouku; - StageFlag = AirBattleData.api_stage_flag; - - LaunchedShipIndexFriend = GetLaunchedShipIndex(0); - LaunchedShipIndexEnemy = GetLaunchedShipIndex(1); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - public override bool IsAvailable => RawData.api_friendly_kouku(); - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) - return; - - var friendHps = Battle.FriendlySupportInfo.FriendlyInitialHPs.ToArray(); - - for (int i = 0; i < TorpedoFlags.Length; i++) - { - int attackType = (TorpedoFlags[i] > 0 ? 1 : 0) | (BomberFlags[i] > 0 ? 2 : 0); - if (attackType > 0) - { - bool isEnemy = new BattleIndex(i, false, Battle.IsEnemyCombined).IsEnemy; - - - // 航空戦は miss/hit=0, critical=1 のため +1 する(通常は miss=0, hit=1, critical=2) - BattleDetails.Add(new BattleFriendlyAirDetail( - Battle, - new BattleIndex(i, Battle.IsFriendCombined, Battle.IsEnemyCombined), - Damages[i], - Criticals[i] + 1, - attackType, - isEnemy ? hps[i] : friendHps[i])); - - if (isEnemy) - AddDamage(hps, i, (int)Damages[i]); - } - } - } - - protected override IEnumerable SearchBattleDetails(int index) - { - return BattleDetails.Where(d => d.DefenderIndex.IsEnemy && d.DefenderIndex == index); - } - - public override string AACutInShipName => Battle.FriendlySupportInfo.FriendlyMembersInstance[AACutInIndex].Name + " Lv. " + Battle.FriendlySupportInfo.FriendlyLevels[AACutInIndex]; -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyShelling.cs b/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyShelling.cs deleted file mode 100644 index 683b74ba1..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlyShelling.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 夜戦における友軍艦隊砲撃フェーズの処理を行います。 -/// -public class PhaseFriendlyShelling : PhaseBase -{ - public PhaseFriendlyShelling(BattleData battle, string title) - : base(battle, title) - { - if (!IsAvailable) - return; - - // battle translation - - int[] fleetflag = (int[])ShellingData.api_at_eflag; - int[] attackers = (int[])ShellingData.api_at_list; - int[] nightAirAttackFlags = (int[])ShellingData.api_n_mother_list; - int[] attackTypes = (int[])ShellingData.api_sp_list; - int[][] defenders = ((dynamic[])ShellingData.api_df_list).Select(elem => ((int[])elem).Where(e => e != -1).ToArray()).ToArray(); - int[][] attackEquipments = ((dynamic[])ShellingData.api_si_list).Select(elem => ((dynamic[])elem).Select(ch => ch is string ? int.Parse(ch) : (int)ch).ToArray()).ToArray(); - int[][] criticals = ((dynamic[])ShellingData.api_cl_list).Select(elem => ((int[])elem).Where(e => e != -1).ToArray()).ToArray(); - double[][] rawDamages = ((dynamic[])ShellingData.api_damage).Select(elem => ((double[])elem).Where(e => e != -1).ToArray()).ToArray(); - - Attacks = new List(); - - - - for (int i = 0; i < attackers.Length; i++) - { - var attack = new PhaseFriendlySupportAttack - { - Attacker = new BattleIndex(attackers[i] + (fleetflag[i] == 0 ? 0 : 12), false, Battle.IsEnemyCombined), - NightAirAttackFlag = nightAirAttackFlags[i] == -1, - AttackType = attackTypes[i], - EquipmentIDs = attackEquipments[i], - }; - for (int k = 0; k < defenders[i].Length; k++) - { - var defender = new PhaseFriendlySupportDefender - { - Defender = new BattleIndex(defenders[i][k] + (fleetflag[i] == 0 ? 12 : 0), false, Battle.IsEnemyCombined), - CriticalFlag = criticals[i][k], - RawDamage = rawDamages[i][k] - }; - attack.Defenders.Add(defender); - } - - Attacks.Add(attack); - } - } - - public override bool IsAvailable => RawData.api_friendly_battle(); - - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) - return; - - int[] friendhps = Battle.FriendlySupportInfo.FriendlyInitialHPs; - - foreach (var attack in Attacks) - { - foreach (var defs in attack.Defenders.GroupBy(d => d.Defender)) - { - BattleDetails.Add(new BattleFriendlyShellingDetail( - (BattleNight)Battle, - attack.Attacker, - defs.Key, - defs.Select(d => d.RawDamage).ToArray(), - defs.Select(d => d.CriticalFlag).ToArray(), - attack.AttackType, - attack.EquipmentIDs, - attack.NightAirAttackFlag, - defs.Key.IsFriend ? friendhps[defs.Key] : hps[defs.Key])); - - if (defs.Key.IsFriend) - friendhps[defs.Key] -= Math.Max(defs.Sum(d => d.Damage), 0); - else - AddDamage(hps, defs.Key, defs.Sum(d => d.Damage)); - } - } - - } - - - - /// - /// 戦闘データ - /// - public dynamic BattleData => RawData.api_friendly_battle; - - /// - /// 砲撃戦データ - /// - public dynamic ShellingData => RawData.api_friendly_battle.api_hougeki; - - - - /// - /// 自軍照明弾投射艦インデックス - /// - public int FlareIndexFriend => (int)BattleData.api_flare_pos[0]; - - /// - /// 敵軍照明弾投射艦インデックス - /// - public int FlareIndexEnemy => (int)BattleData.api_flare_pos[1]; - - - /// - /// 自軍照明弾投射艦 - /// - public IShipDataMaster FlareFriendInstance - { - get - { - int index = FlareIndexFriend; - if (0 <= index && index < Battle.FriendlySupportInfo.FriendlyMembersInstance.Length) - return Battle.FriendlySupportInfo.FriendlyMembersInstance[index]; - return null; - } - } - - /// - /// 敵軍照明弾投射艦 - /// - public IShipDataMaster FlareEnemyInstance - { - get - { - int index = FlareIndexEnemy; - var nightinitial = (Battle as BattleNight)?.NightInitial; - - if (nightinitial != null && - 0 <= index && index < nightinitial.EnemyMembersInstance.Length) - return nightinitial.EnemyMembersInstance[index]; - return null; - } - } - - - /// - /// 自軍探照灯照射艦番号 - /// - public int SearchlightIndexFriend - { - get - { - int index = -1; - var eqmaster = KCDatabase.Instance.MasterEquipments; - - for (int i = 0; i < Battle.FriendlySupportInfo.FriendlyMembersInstance.Length; i++) - { - if (Battle.FriendlySupportInfo.FriendlyMembers[i] != -1 && Battle.FriendlySupportInfo.FriendlyInitialHPs[i] > 1) - { - if (Battle.FriendlySupportInfo.FriendlySlots[i].Any(id => eqmaster[id]?.CategoryType == EquipmentTypes.SearchlightLarge)) - return i; - else if (Battle.FriendlySupportInfo.FriendlySlots[i].Any(id => eqmaster[id]?.CategoryType == EquipmentTypes.Searchlight) && index == -1) - index = i; - } - } - - return index; - } - } - - - /// - /// 敵軍探照灯照射艦番号 - /// 厳密には異なるが(友軍の攻撃で探照灯所持艦の HP が 1 になった場合 -1 になる)、めったに起こるものでもないので気にしないことにする - /// - public int SearchlightIndexEnemy => (Battle as BattleNight)?.NightInitial?.SearchlightIndexEnemy ?? -1; - - - /// - /// 自軍探照灯照射艦 - /// - public IShipDataMaster SearchlightFriendInstance - { - get - { - int index = SearchlightIndexFriend; - if (0 <= index && index < Battle.FriendlySupportInfo.FriendlyMembersInstance.Length) - return Battle.FriendlySupportInfo.FriendlyMembersInstance[index]; - return null; - } - } - - /// - /// 敵軍探照灯投射艦 - /// - public IShipDataMaster SearchlightEnemyInstance - { - get - { - int index = SearchlightIndexEnemy; - var nightinitial = (Battle as BattleNight)?.NightInitial; - - if (nightinitial != null && - 0 <= index && index < nightinitial.EnemyMembersInstance.Length) - return nightinitial.EnemyMembersInstance[index]; - return null; - } - } - - - - public List Attacks { get; private set; } - - - public class PhaseFriendlySupportAttack - { - public BattleIndex Attacker; - public int AttackType; - public bool NightAirAttackFlag; - public List Defenders; - public int[] EquipmentIDs; - - public PhaseFriendlySupportAttack() - { - Defenders = new List(); - } - } - - public class PhaseFriendlySupportDefender - { - public BattleIndex Defender; - public int CriticalFlag; - public double RawDamage; - public bool GuardsFlagship => RawDamage != Math.Floor(RawDamage); - public int Damage => (int)RawDamage; - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlySupportInfo.cs b/ElectronicObserver/Data/Battle/Phase/PhaseFriendlySupportInfo.cs deleted file mode 100644 index ae94329be..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseFriendlySupportInfo.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Linq; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 友軍艦隊の情報を処理します。 -/// -public class PhaseFriendlySupportInfo : PhaseBase -{ - public PhaseFriendlySupportInfo(BattleData battle, string title) - : base(battle, title) - { - if (!IsAvailable) - return; - - // info translation - - int[] GetArrayOrDefault(string objectName, int length) => !InfoData.IsDefined(objectName) ? null : FixedArray((int[])InfoData[objectName], length); - int[][] GetArraysOrDefault(string objectName, int topLength, int bottomLength) - { - if (!InfoData.IsDefined(objectName)) - return null; - - int[][] ret = new int[topLength][]; - dynamic[] raw = (dynamic[])InfoData[objectName]; - for (int i = 0; i < ret.Length; i++) - { - if (i < raw.Length) - ret[i] = FixedArray((int[])raw[i], bottomLength); - else - ret[i] = Enumerable.Repeat(-1, bottomLength).ToArray(); - } - return ret; - } - - FriendlyMembers = GetArrayOrDefault("api_ship_id", 7); - FriendlyMembersInstance = FriendlyMembers.Select(id => KCDatabase.Instance.MasterShips[id]).ToArray(); - FriendlyLevels = GetArrayOrDefault("api_ship_lv", 7); - FriendlyInitialHPs = GetArrayOrDefault("api_nowhps", 7); - FriendlyMaxHPs = GetArrayOrDefault("api_maxhps", 7); - - FriendlySlots = GetArraysOrDefault("api_Slot", 7, 5); - FriendlyExpansionSlots = GetArrayOrDefault("api_slot_ex", 7); - FriendlyParameters = GetArraysOrDefault("api_Param", 7, 4); - } - - public override bool IsAvailable => RawData.api_friendly_info(); - - public override void EmulateBattle(int[] hps, int[] damages) - { - // nop - } - - - /// - /// 友軍情報 - /// - public dynamic InfoData => RawData.api_friendly_info; - - /// - /// 種別? - /// - public int Type => (int)InfoData.api_production_type; - - - /// - /// 友軍艦隊ID - /// - public int[] FriendlyMembers { get; private set; } - - /// - /// 友軍艦隊 - /// - public IShipDataMaster[] FriendlyMembersInstance { get; private set; } - - - /// - /// 友軍艦隊レベル - /// - public int[] FriendlyLevels { get; private set; } - - /// - /// 友軍艦隊初期HP - /// - public int[] FriendlyInitialHPs { get; private set; } - - /// - /// 友軍艦隊最大HP - /// - public int[] FriendlyMaxHPs { get; private set; } - - - /// - /// 友軍艦隊装備 - /// - public int[][] FriendlySlots { get; private set; } - - /// - /// 友軍艦隊装備 (拡張スロット) - /// - public int[] FriendlyExpansionSlots { get; private set; } - - /// - /// 友軍艦隊パラメータ - /// - public int[][] FriendlyParameters { get; private set; } - - // api_voice_id - // api_voice_p_no - - - - protected static int[] FixedArray(int[] array, int length, int defaultValue = -1) - { - var ret = new int[length]; - int l = Math.Min(length, array.Length); - Array.Copy(array, ret, l); - if (l < length) - { - for (int i = l; i < length; i++) - ret[i] = defaultValue; - } - - return ret; - } -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Data/Battle/Phase/PhaseInitial.cs deleted file mode 100644 index 65b62e2c0..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseInitial.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserverTypes; -using ElectronicObserverTypes.Mocks; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 戦闘開始フェーズの処理を行います。 -/// -public class PhaseInitial : PhaseBase -{ - - /// - /// 自軍艦隊ID - /// - public int FriendFleetID { get; private set; } - - /// - /// 自軍艦隊 - /// - public FleetData FriendFleet => KCDatabase.Instance.Fleet[FriendFleetID]; - - /// - /// 自軍随伴艦隊 - /// - public FleetData FriendFleetEscort => IsFriendCombined ? KCDatabase.Instance.Fleet[2] : null; - - - /// - /// 敵艦隊メンバ - /// - public int[] EnemyMembers { get; private set; } - - /// - /// 敵艦隊メンバ - /// - public IShipDataMaster?[] EnemyMembersInstance { get; private set; } - - - /// - /// 敵艦隊メンバ(随伴艦隊) - /// - public int[]? EnemyMembersEscort { get; private set; } - - /// - /// 敵艦隊メンバ(随伴艦隊) - /// - public IShipDataMaster?[]? EnemyMembersEscortInstance { get; private set; } - - public IFleetData EnemyFleet { get; private set; } - - public IFleetData? EnemyFleetEscort { get; private set; } - - /// - /// 敵艦のレベル - /// - public int[] EnemyLevels { get; private set; } - - /// - /// 敵艦のレベル(随伴艦隊) - /// - public int[]? EnemyLevelsEscort { get; private set; } - - - public int[] FriendInitialHPs { get; private set; } - public int[]? FriendInitialHPsEscort { get; private set; } - public int[] EnemyInitialHPs { get; private set; } - public int[]? EnemyInitialHPsEscort { get; private set; } - - public int[] FriendMaxHPs { get; private set; } - public int[]? FriendMaxHPsEscort { get; private set; } - public int[] EnemyMaxHPs { get; private set; } - public int[]? EnemyMaxHPsEscort { get; private set; } - - public bool[] IsEnemyTargetable { get; } - public bool[] IsEnemyTargetableEscort { get; } - - - /// - /// 敵艦のスロット - /// - public int[][] EnemySlots { get; private set; } - - /// - /// 敵艦のスロット - /// - public IEquipmentDataMaster[][] EnemySlotsInstance { get; private set; } - - - /// - /// 敵艦のスロット(随伴艦隊) - /// - public int[][] EnemySlotsEscort { get; private set; } - - /// - /// 敵艦のスロット(随伴艦隊) - /// - public IEquipmentDataMaster[][]? EnemySlotsEscortInstance { get; private set; } - - - /// - /// 敵艦のパラメータ - /// - public int[][] EnemyParameters { get; private set; } - - /// - /// 敵艦のパラメータ(随伴艦隊) - /// - public int[][] EnemyParametersEscort { get; private set; } - - - /// - /// 装甲破壊されているか - /// - public bool IsBossDamaged => RawData.api_xal01() && (int)RawData.api_xal01 > 0; - - - /// - /// 戦闘糧食を食べた艦娘のインデックス [0-11] - /// - public int[] RationIndexes { get; private set; } - - - public bool IsFriendCombined => FriendInitialHPsEscort != null; - public bool IsEnemyCombined => EnemyInitialHPsEscort != null; - - - - public PhaseInitial(BattleData data, string title) - : base(data, title) - { - { - dynamic id = RawData.api_dock_id() ? RawData.api_dock_id : - RawData.api_deck_id() ? RawData.api_deck_id : 1; - FriendFleetID = id is string ? int.Parse((string)id) : (int)id; - } - if (FriendFleetID <= 0) - FriendFleetID = 1; - - - int[]? GetArrayOrDefault(string objectName, int length) - { - object[]? values = RawData.IsDefined(objectName) switch - { - true => RawData[objectName].Deserialize(), - _ => null, - }; - - if (values is null) return null; - - int[] cleanedValues = values - .Select(v => v switch - { - double d => (int?)d, - int i => i, - // enemy HP and max HP can have "N/A" as a value for untargetable enemies - // this value then gets updated to the real HP value in HandleTargetability - string => -2, - _ => null, - }) - .Where(v => v is not null) - .Select(v => v!.Value) - .ToArray(); - - return FixedArray(cleanedValues, length); - } - - int[][] GetArraysOrDefault(string objectName, int topLength, int bottomLength) - { - if (!RawData.IsDefined(objectName)) - return null; - - int[][] ret = new int[topLength][]; - dynamic[] raw = (dynamic[])RawData[objectName]; - for (int i = 0; i < ret.Length; i++) - { - if (i < raw.Length) - ret[i] = FixedArray((int[])raw[i], bottomLength); - else - ret[i] = Enumerable.Repeat(-1, bottomLength).ToArray(); - } - return ret; - } - - int[]? HandleTargetability(int[]? hps, IShipDataMaster?[]? ships, bool[] isTargetable) - { - if (hps is null) return null; - if (ships is null) return null; - - for (int i = 0; i < hps.Length; i++) - { - if (hps[i] is not -2) continue; - if (ships[i] is not {} ship) continue; - - isTargetable[i] = false; - hps[i] = ship.HPMax; - } - - return hps; - } - - int mainMemberCount = 7; - int escortMemberCount = 6; - - IsEnemyTargetable = new[] { true, true, true, true, true, true, true }; - IsEnemyTargetableEscort = new[] { true, true, true, true, true, true }; - - EnemyMembers = GetArrayOrDefault("api_ship_ke", mainMemberCount)!; - EnemyMembersInstance = EnemyMembers.Select(id => KCDatabase.Instance.MasterShips[id]).ToArray(); - - EnemyMembersEscort = GetArrayOrDefault("api_ship_ke_combined", escortMemberCount); - EnemyMembersEscortInstance = EnemyMembersEscort?.Select(id => KCDatabase.Instance.MasterShips[id]).ToArray(); - - EnemyLevels = GetArrayOrDefault("api_ship_lv", mainMemberCount)!; - EnemyLevelsEscort = GetArrayOrDefault("api_ship_lv_combined", escortMemberCount); - - FriendInitialHPs = GetArrayOrDefault("api_f_nowhps", mainMemberCount)!; - FriendInitialHPsEscort = GetArrayOrDefault("api_f_nowhps_combined", escortMemberCount); - EnemyInitialHPs = HandleTargetability(GetArrayOrDefault("api_e_nowhps", mainMemberCount), EnemyMembersInstance, IsEnemyTargetable)!; - EnemyInitialHPsEscort = HandleTargetability(GetArrayOrDefault("api_e_nowhps_combined", escortMemberCount), EnemyMembersEscortInstance, IsEnemyTargetableEscort); - - FriendMaxHPs = GetArrayOrDefault("api_f_maxhps", mainMemberCount)!; - FriendMaxHPsEscort = GetArrayOrDefault("api_f_maxhps_combined", escortMemberCount); - EnemyMaxHPs = HandleTargetability(GetArrayOrDefault("api_e_maxhps", mainMemberCount), EnemyMembersInstance, IsEnemyTargetable)!; - EnemyMaxHPsEscort = HandleTargetability(GetArrayOrDefault("api_e_maxhps_combined", escortMemberCount), EnemyMembersEscortInstance, IsEnemyTargetableEscort); - - - EnemySlots = GetArraysOrDefault("api_eSlot", mainMemberCount, 5); - EnemySlotsInstance = EnemySlots.Select(part => part.Select(id => KCDatabase.Instance.MasterEquipments[id]).ToArray()).ToArray(); - - EnemySlotsEscort = GetArraysOrDefault("api_eSlot_combined", escortMemberCount, 5); - EnemySlotsEscortInstance = EnemySlotsEscort?.Select(part => part.Select(id => KCDatabase.Instance.MasterEquipments[id]).ToArray()).ToArray(); - - EnemyParameters = GetArraysOrDefault("api_eParam", mainMemberCount, 4); - EnemyParametersEscort = GetArraysOrDefault("api_eParam_combined", escortMemberCount, 4); - - InitializeEnemyFleets(); - - var rations = new List(); - if (RawData.api_combat_ration()) - { - rations.AddRange(((int[])RawData.api_combat_ration).Select(i => FriendFleet.Members.IndexOf(i))); - } - if (RawData.api_combat_ration_combined()) - { - rations.AddRange(((int[])RawData.api_combat_ration_combined).Select(i => FriendFleetEscort.Members.IndexOf(i) + 6)); - } - RationIndexes = rations.ToArray(); - } - - private void InitializeEnemyFleets() - { - EnemyFleet = new FleetDataMock - { - MembersInstance = new(EnemyMembersInstance - .OfType() - .Select(shipMaster => new ShipDataMock(shipMaster)) - .Cast() - .ToList()), - }; - - for (int index = 0; index < EnemyFleet.MembersInstance.Count; index++) - { - if (EnemyFleet.MembersInstance[index] is ShipDataMock ship) - { - ship.CanBeTargeted = IsEnemyTargetable[index]; - } - } - - EnemyFleetEscort = null; - - if (EnemyMembersEscortInstance is not null) - { - EnemyFleetEscort = new FleetDataMock() - { - MembersInstance = new(EnemyMembersEscortInstance - .OfType() - .Select(shipMaster => new ShipDataMock(shipMaster)) - .Cast() - .ToList()), - }; - - for (int index = 0; index < EnemyFleetEscort.MembersInstance.Count; index++) - { - if (EnemyFleetEscort.MembersInstance[index] is ShipDataMock ship) - { - ship.CanBeTargeted = IsEnemyTargetableEscort[index]; - } - } - } - } - - public IShipData GetFriendShip(int index) - { - if (index < 0 || index >= 12) - return null; - - if (index < FriendFleet.Members.Count) - return FriendFleet.MembersInstance[index]; - else if (index >= 6 && FriendFleetEscort != null) - return FriendFleetEscort.MembersInstance[index - 6]; - else - return null; - } - - protected static int[] FixedArray(int[] array, int length, int defaultValue = -1) - { - var ret = new int[length]; - int l = Math.Min(length, array.Length); - Array.Copy(array, ret, l); - if (l < length) - { - for (int i = l; i < length; i++) - ret[i] = defaultValue; - } - - return ret; - } - - public override bool IsAvailable => RawData != null; - - public override void EmulateBattle(int[] hps, int[] damages) - { - } -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseJetAirBattle.cs b/ElectronicObserver/Data/Battle/Phase/PhaseJetAirBattle.cs deleted file mode 100644 index b70c63e08..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseJetAirBattle.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 噴式強襲航空攻撃フェーズの処理を行います。 -/// -public class PhaseJetAirBattle : PhaseAirBattleBase -{ - - public PhaseJetAirBattle(BattleData data, string title) - : base(data, title) - { - - AirBattleData = RawData.api_injection_kouku() ? RawData.api_injection_kouku : null; - if (AirBattleData != null) - { - StageFlag = new int[] { - AirBattleData.api_stage1() ? 1 : 0, - AirBattleData.api_stage2() ? 1 : 0, - AirBattleData.api_stage3() ? 1 : 0, - }; - } - - LaunchedShipIndexFriend = GetLaunchedShipIndex(0); - LaunchedShipIndexEnemy = GetLaunchedShipIndex(1); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) return; - - CalculateAttack(0, hps); - CalculateAttackDamage(damages); - } - - - /// - /// 航空戦での与ダメージを推測します。 - /// - /// 与ダメージリスト。 - private void CalculateAttackDamage(int[] damages) - { - // 敵はめんどくさすぎるので省略 - // 仮想火力を求め、それに従って合計ダメージを分配 - - var firepower = new int[12]; - var launchedIndex = LaunchedShipIndexFriend; - var members = Battle.Initial.FriendFleet.MembersWithoutEscaped; - - foreach (int i in launchedIndex) - { - - IShipData ship = Battle.Initial.GetFriendShip(i); - if (ship == null) - continue; - - var slots = ship.SlotInstanceMaster; - var aircrafts = ship.Aircraft; - for (int s = 0; s < slots.Count; s++) - { - - if (slots[s] == null) - continue; - - switch (slots[s].CategoryType) - { - case EquipmentTypes.JetBomber: - firepower[i] += (int)(1.0 * (slots[s].Bomber * Math.Sqrt(aircrafts[s]) + 25)); - break; - - // 噴式攻撃機 (80%と150%はランダムのため係数は平均値) - case EquipmentTypes.JetTorpedo: - firepower[i] += (int)(1.15 * (slots[s].Torpedo * Math.Sqrt(aircrafts[s]) + 25)); - break; - } - } - } - - int totalFirepower = firepower.Sum(); - int totalDamage = Damages.Select(dmg => (int)dmg).Skip(12).Take(12).Sum(); - - for (int i = 0; i < firepower.Length; i++) - { - damages[i] += (int)Math.Round((double)totalDamage * firepower[i] / Math.Max(totalFirepower, 1)); - } - } - - - protected override IEnumerable SearchBattleDetails(int index) - { - return BattleDetails.Where(d => d.DefenderIndex == index); - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseJetBaseAirAttack.cs b/ElectronicObserver/Data/Battle/Phase/PhaseJetBaseAirAttack.cs deleted file mode 100644 index bad20ac98..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseJetBaseAirAttack.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 噴式航空機による基地航空隊攻撃フェーズの処理を行います。 -/// -public class PhaseJetBaseAirAttack : PhaseBase -{ - - /// - /// 噴式航空機による基地航空隊攻撃フェーズの、個々の攻撃フェーズの処理を行います。 - /// - public class PhaseJetBaseAirAttackUnit : PhaseAirBattleBase - { - - public PhaseJetBaseAirAttackUnit(BattleData data, string title, int index) - : base(data, title) - { - - if (index == -1) - { - AirAttackIndex = 0; - AirBattleData = data.RawData.api_air_base_injection; - } - else - { - AirAttackIndex = index; - AirBattleData = data.RawData.api_air_base_injection[index]; - } - - if (AirBattleData != null) - { - StageFlag = new int[] { - AirBattleData.api_stage1() ? 1 : 0, - AirBattleData.api_stage2() ? 1 : 0, - AirBattleData.api_stage3() ? 1 : 0, - }; - } - - _squadrons = GetSquadrons().ToArray(); - - TorpedoFlags = ConcatStage3Array("api_frai_flag", "api_erai_flag"); - BomberFlags = ConcatStage3Array("api_fbak_flag", "api_ebak_flag"); - Criticals = ConcatStage3Array("api_fcl_flag", "api_ecl_flag"); - Damages = ConcatStage3Array("api_fdam", "api_edam"); - } - - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) return; - - CalculateAttack(AirAttackIndex + 1, hps); - } - - - /// - /// 攻撃ID (第n波, 0から始まる) - /// - public int AirAttackIndex { get; private set; } - - - private BattleBaseAirCorpsSquadron[] _squadrons; - /// - /// 参加した航空中隊データ - /// - public ReadOnlyCollection Squadrons => Array.AsReadOnly(_squadrons); - - private IEnumerable GetSquadrons() - { - foreach (dynamic d in AirBattleData.api_air_base_data) - yield return new BattleBaseAirCorpsSquadron(d); - } - - } - - - - public PhaseJetBaseAirAttack(BattleData data, string title) - : base(data, title) - { - - AirAttackUnits = new List(); - - if (!IsAvailable) - return; - - - dynamic attackData = RawData.api_air_base_injection; - if (attackData.IsArray) - { - int i = 0; - foreach (var unit in RawData.api_air_base_injection) - { - AirAttackUnits.Add(new PhaseJetBaseAirAttackUnit(data, title, i)); - i++; - } - - } - else if (attackData.IsObject) - { - AirAttackUnits.Add(new PhaseJetBaseAirAttackUnit(data, title, -1)); - } - } - - - /// - /// 個々の攻撃フェーズのデータ - /// - public List AirAttackUnits { get; private set; } - - - - public override bool IsAvailable => RawData.api_air_base_injection(); - - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) - return; - - foreach (var a in AirAttackUnits) - { - - a.EmulateBattle(hps, damages); - } - } - - - protected override IEnumerable SearchBattleDetails(int index) - { - return AirAttackUnits.SelectMany(p => p.BattleDetails).Where(d => d.DefenderIndex == index); - } -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseNightBattle.cs b/ElectronicObserver/Data/Battle/Phase/PhaseNightBattle.cs deleted file mode 100644 index 7b4ee5d6f..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseNightBattle.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes.Attacks; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 夜戦フェーズの処理を行います。 -/// -public class PhaseNightBattle : PhaseBase -{ - - private readonly int PhaseID; - - - public PhaseNightBattle(BattleData data, string title, int phaseID) - : base(data, title) - { - - PhaseID = phaseID; - - - if (!IsAvailable) - return; - - - int[] fleetflag = (int[])ShellingData.api_at_eflag; - int[] attackers = (int[])ShellingData.api_at_list; - int[] nightAirAttackFlags = (int[])ShellingData.api_n_mother_list; - int[] attackTypes = (int[])ShellingData.api_sp_list; - int[][] defenders = ((dynamic[])ShellingData.api_df_list).Select(elem => ((int[])elem).Where(e => e != -1).ToArray()).ToArray(); - int[][] attackEquipments = ((dynamic[])ShellingData.api_si_list).Select(elem => ((dynamic[])elem).Select(ch => ch is string ? int.Parse(ch) : (int)ch).ToArray()).ToArray(); - int[][] criticals = ((dynamic[])ShellingData.api_cl_list).Select(elem => ((int[])elem).Where(e => e != -1).ToArray()).ToArray(); - double[][] rawDamages = ((dynamic[])ShellingData.api_damage).Select(elem => ((double[])elem).Where(e => e != -1).ToArray()).ToArray(); - - Attacks = new List(); - - - - for (int i = 0; i < attackers.Length; i++) - { - var attack = new PhaseNightBattleAttack - { - Attacker = new BattleIndex(attackers[i] + (fleetflag[i] == 0 ? 0 : 12), Battle.IsFriendCombined, Battle.IsEnemyCombined), - NightAirAttackFlag = nightAirAttackFlags[i] == -1, - AttackType = attackTypes[i], - EquipmentIDs = attackEquipments[i], - }; - for (int k = 0; k < defenders[i].Length; k++) - { - var defender = new PhaseNightBattleDefender - { - Defender = new BattleIndex(defenders[i][k] + (fleetflag[i] == 0 ? 12 : 0), Battle.IsFriendCombined, Battle.IsEnemyCombined), - CriticalFlag = criticals[i][k], - RawDamage = rawDamages[i][k] - }; - attack.Defenders.Add(defender); - } - - Attacks.Add(attack); - } - - } - - public override bool IsAvailable => - RawData.IsDefined(ShellingDataName) && - RawData[ShellingDataName].api_at_list() && - RawData[ShellingDataName].api_at_list != null; - - - public dynamic ShellingData => RawData[ShellingDataName]; - - private string ShellingDataName => PhaseID == 0 ? "api_hougeki" : ("api_n_hougeki" + PhaseID); - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) return; - - foreach (var atk in Attacks) - { - if (atk.AttackTypeTyped.IsSpecialAttack()) - { - List attackers = atk.AttackTypeTyped switch - { - NightAttackKind.CutinZuiun => Enumerable.Repeat(atk.Attacker.Index, 2).ToList(), - _ => atk.AttackTypeTyped.SpecialAttackIndexes(), - }; - - int fleetCount = KCDatabase.Instance.Fleet.Fleets.Values - .Count(f => f.IsInSortie); - - for (int i = 0; i < atk.Defenders.Count; i++) - { - int attackerIndex = attackers[i]; - - BattleIndex comboatk = fleetCount switch - { - 2 => new(attackerIndex + 6, true, true), - _ => new BattleIndex(atk.Attacker.Side, attackerIndex) - }; - - BattleDetails.Add(new BattleNightDetail(Battle, comboatk, atk.Defenders[i].Defender, new[] { atk.Defenders[i].RawDamage }, new[] { atk.Defenders[i].CriticalFlag }, atk.AttackType, atk.EquipmentIDs, atk.NightAirAttackFlag, hps[atk.Defenders[i].Defender])); - AddDamage(hps, atk.Defenders[i].Defender, atk.Defenders[i].Damage); - damages[comboatk] += atk.Defenders[i].Damage; - } - } - else - { - foreach (var defs in atk.Defenders.GroupBy(d => d.Defender)) - { - BattleDetails.Add(new BattleNightDetail(Battle, atk.Attacker, defs.Key, defs.Select(d => d.RawDamage).ToArray(), defs.Select(d => d.CriticalFlag).ToArray(), atk.AttackType, atk.EquipmentIDs, atk.NightAirAttackFlag, hps[defs.Key])); - AddDamage(hps, defs.Key, defs.Sum(d => d.Damage)); - } - damages[atk.Attacker] += atk.Defenders.Sum(d => d.Damage); - } - } - - } - - - public List Attacks { get; private set; } - public class PhaseNightBattleAttack - { - public BattleIndex Attacker; - - public int AttackType; - - public NightAttackKind AttackTypeTyped => (NightAttackKind)AttackType; - - public bool NightAirAttackFlag; - - public List Defenders; - - public int[] EquipmentIDs; - - public PhaseNightBattleAttack() - { - Defenders = new List(); - } - - public override string ToString() => $"{Attacker}[{AttackType}] -> [{string.Join(", ", Defenders)}]"; - - } - public class PhaseNightBattleDefender - { - public BattleIndex Defender; - public int CriticalFlag; - public double RawDamage; - public bool GuardsFlagship => RawDamage != Math.Floor(RawDamage); - public int Damage => (int)RawDamage; - - public override string ToString() - { - return string.Format("{0};{1}-{2}{3}", Defender, Damage, - CriticalFlag == 0 ? "miss" : CriticalFlag == 1 ? "dmg" : CriticalFlag == 2 ? "crit" : "INVALID", - GuardsFlagship ? " (guard)" : ""); - } - } - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseNightInitial.cs b/ElectronicObserver/Data/Battle/Phase/PhaseNightInitial.cs deleted file mode 100644 index 13bdedb0d..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseNightInitial.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System.Linq; -using ElectronicObserverTypes; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 夜戦開始フェーズの処理を行います。 -/// -public class PhaseNightInitial : PhaseBase -{ - - private readonly bool IsEscort; - - public PhaseNightInitial(BattleData battle, string title, bool isEscort) - : base(battle, title) - { - IsEscort = isEscort; - } - - public override bool IsAvailable => RawData != null; - - public override void EmulateBattle(int[] hps, int[] damages) - { - // nop - } - - - - /// - /// 戦闘する自軍艦隊 - /// 1=主力艦隊, 2=随伴艦隊 - /// - public int ActiveFriendFleet => !RawData.api_active_deck() ? 1 : (int)RawData.api_active_deck[0]; - - /// - /// 自軍艦隊ID - /// - public int FriendFleetID - { - get - { - if (IsFriendEscort) - return 2; - else - return Battle.Initial.FriendFleetID; - } - } - - /// - /// 自軍艦隊 - /// - public FleetData FriendFleet => KCDatabase.Instance.Fleet[FriendFleetID]; - - /// - /// 自軍が随伴艦隊かどうか - /// - public bool IsFriendEscort => IsEscort || ActiveFriendFleet != 1; - - - /// - /// 敵軍艦隊ID - /// - public int EnemyFleetID => !RawData.api_active_deck() ? 1 : (int)RawData.api_active_deck[1]; - - /// - /// 敵軍艦隊 - /// - public int[] EnemyMembers => !IsEnemyEscort ? Battle.Initial.EnemyMembers : Battle.Initial.EnemyMembersEscort; - - /// - /// 敵軍艦隊 - /// - public IShipDataMaster[] EnemyMembersInstance => !IsEnemyEscort ? Battle.Initial.EnemyMembersInstance : Battle.Initial.EnemyMembersEscortInstance; - - /// - /// 敵軍が随伴艦隊かどうか - /// - public bool IsEnemyEscort => EnemyFleetID != 1; - - - /// - /// 自軍触接機ID - /// - public int TouchAircraftFriend => (RawData.api_touch_plane[0] is string) ? int.Parse(RawData.api_touch_plane[0]) : (int)RawData.api_touch_plane[0]; - - - /// - /// 敵軍触接機ID - /// - public int TouchAircraftEnemy => (RawData.api_touch_plane[1] is string) ? int.Parse(RawData.api_touch_plane[1]) : (int)RawData.api_touch_plane[1]; - - - /// - /// 自軍照明弾投射艦インデックス(0-11, -1=発動せず) - /// - public int FlareIndexFriend => (int)RawData.api_flare_pos[0]; - - /// - /// 敵軍照明弾投射艦インデックス(0-11, -1=発動せず) - /// - public int FlareIndexEnemy => (int)RawData.api_flare_pos[1]; - - - /// - /// 自軍照明弾投射艦 - /// - public IShipData FlareFriendInstance - { - get - { - int index = FlareIndexFriend; - - if (index < 0) - return null; - - if (IsFriendEscort) - return FriendFleet.MembersInstance[index - 6]; - else - return FriendFleet.MembersInstance[index]; - - } - } - - /// - /// 敵軍照明弾投射艦 - /// - public IShipDataMaster FlareEnemyInstance - { - get - { - int index = FlareIndexEnemy; - - if (index < 0) - return null; - - if (IsEnemyEscort) - return EnemyMembersInstance[index - 6]; - else - return EnemyMembersInstance[index]; - } - } - - - /// - /// 自軍探照灯照射艦番号 - /// - public int SearchlightIndexFriend - { - get - { - var ships = FriendFleet.MembersWithoutEscaped; - var hps = IsFriendEscort ? Battle.Initial.FriendInitialHPsEscort : Battle.Initial.FriendInitialHPs; - int index = -1; - - for (int i = 0; i < ships.Count; i++) - { - var ship = ships[i]; - if (ship != null && hps[i] > 1) - { - - if (ship.SlotInstanceMaster.Any(e => e?.CategoryType == EquipmentTypes.SearchlightLarge)) - return i; - else if (ship.SlotInstanceMaster.Any(e => e?.CategoryType == EquipmentTypes.Searchlight) && index == -1) - index = i; - } - } - - return index; - } - } - - /// - /// 敵軍探照灯照射艦番号(0-5) - /// - public int SearchlightIndexEnemy - { - get - { - var ships = EnemyMembersInstance; - var eqs = Battle.Initial.EnemySlotsInstance; - var hps = IsEnemyEscort ? Battle.Initial.EnemyInitialHPsEscort : Battle.Initial.EnemyInitialHPs; - int index = -1; - - for (int i = 0; i < ships.Length; i++) - { - if (ships[i] != null && hps[i] > 1) - { - - if (eqs[i].Any(e => e?.CategoryType == EquipmentTypes.SearchlightLarge)) - return i; - else if (eqs[i].Any(e => e?.CategoryType == EquipmentTypes.Searchlight) && index == -1) - index = i; - - } - } - - return index; - } - } - - /// - /// 敵軍探照灯照射艦 - /// - public IShipDataMaster SearchlightEnemyInstance - { - get - { - int index = SearchlightIndexEnemy; - return index == -1 ? null : EnemyMembersInstance[index]; - } - } - - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseOpeningASW.cs b/ElectronicObserver/Data/Battle/Phase/PhaseOpeningASW.cs deleted file mode 100644 index 5eba66859..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseOpeningASW.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 開幕対潜攻撃フェーズの処理を行います。 -/// -public class PhaseOpeningASW : PhaseShelling -{ - - // 砲撃戦とフォーマットが同じなので流用 - - public PhaseOpeningASW(BattleData data, string title) - : base(data, title, 0, "") - { - - } - - public override bool IsAvailable => (int)RawData.api_opening_taisen_flag != 0; - - public override dynamic ShellingData => RawData.api_opening_taisen; -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseRadar.cs b/ElectronicObserver/Data/Battle/Phase/PhaseRadar.cs deleted file mode 100644 index 8c2a99db4..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseRadar.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// レーダー射撃フェーズの処理を行います。 -/// -public class PhaseRadar : PhaseShelling -{ - - // 砲撃戦とフォーマットが同じなので流用 - - public PhaseRadar(BattleData data, string title) - : base(data, title, 1, "1") - { - } - - public override bool IsAvailable => RawData.api_hougeki1() && RawData.api_hougeki1 != null; - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseSearching.cs b/ElectronicObserver/Data/Battle/Phase/PhaseSearching.cs deleted file mode 100644 index 8be53ef57..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseSearching.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 索敵フェーズの処理を行います。 -/// -public class PhaseSearching : PhaseBase -{ - - - public PhaseSearching(BattleData data, string title) - : base(data, title) { } - - - public override bool IsAvailable => RawData.api_search() && RawData.api_formation(); - - public override void EmulateBattle(int[] hps, int[] damages) - { - } - - - /// - /// 自軍索敵結果 - /// - public int SearchingFriend => !RawData.api_search() ? -1 : (int)RawData.api_search[0]; - - - /// - /// 敵軍索敵結果 - /// - public int SearchingEnemy => !RawData.api_search() ? -1 : (int)RawData.api_search[1]; - - - /// - /// 自軍陣形 - /// - public int FormationFriend - { - get - { - dynamic form = RawData.api_formation[0]; - return form is string ? int.Parse((string)form) : (int)form; - } - } - - /// - /// 敵軍陣形 - /// - public int FormationEnemy => (int)RawData.api_formation[1]; - - /// - /// 交戦形態 - /// - public int EngagementForm => (int)RawData.api_formation[2]; - - /// - /// 0, 1, 2, 3 - number of active smokers
- /// null - no idea when this can be null - ///
- public int? SmokeCount => RawData.api_smoke_type() switch - { - true => (int)RawData.api_smoke_type, - _ => null, - }; -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseShelling.cs b/ElectronicObserver/Data/Battle/Phase/PhaseShelling.cs deleted file mode 100644 index 5ac8f49a5..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseShelling.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserverTypes.Attacks; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 砲撃戦フェーズの処理を行います。 -/// -public class PhaseShelling : PhaseBase -{ - protected readonly int PhaseID; - protected readonly string Suffix; - - public List Attacks { get; private set; } - - public class PhaseShellingAttack - { - public BattleIndex Attacker; - - public int AttackType; - - public DayAttackKind AttackTypeTyped => (DayAttackKind)AttackType; - - public List Defenders; - - public int[] EquipmentIDs; - - public PhaseShellingAttack() - { - Defenders = new List(); - } - - public override string ToString() => $"{Attacker}[{AttackType}] -> [{string.Join(", ", Defenders)}]"; - - } - public class PhaseShellingDefender - { - public BattleIndex Defender; - public int CriticalFlag; - public double RawDamage; - public bool GuardsFlagship => RawDamage != Math.Floor(RawDamage); - public int Damage => (int)RawDamage; - - public override string ToString() - { - return string.Format("{0};{1}-{2}{3}", Defender, Damage, - CriticalFlag == 0 ? "miss" : CriticalFlag == 1 ? "dmg" : CriticalFlag == 2 ? "crit" : "INVALID", - GuardsFlagship ? " (guard)" : ""); - } - } - - public PhaseShelling(BattleData data, string title, int phaseID, string suffix) - : base(data, title) - { - - PhaseID = phaseID; - Suffix = suffix; - - if (!IsAvailable) - return; - - // "translate" - - int[] fleetflag = (int[])ShellingData.api_at_eflag; - int[] attackers = (int[])ShellingData.api_at_list; - int[] attackTypes = (int[])ShellingData.api_at_type; - int[][] defenders = ((dynamic[])ShellingData.api_df_list).Select(elem => (int[])elem).ToArray(); - int[][] attackEquipments = ((dynamic[])ShellingData.api_si_list).Select(elem => ((dynamic[])elem).Select(ch => ch is string ? int.Parse(ch) : (int)ch).ToArray()).ToArray(); - int[][] criticalFlags = ((dynamic[])ShellingData.api_cl_list).Select(elem => (int[])elem).ToArray(); - double[][] rawDamages = ((dynamic[])ShellingData.api_damage).Select(elem => ((double[])elem).Select(p => Math.Max(p, 0)).ToArray()).ToArray(); - - Attacks = new List(); - - for (int i = 0; i < attackers.Length; i++) - { - var attack = new PhaseShellingAttack() - { - Attacker = new BattleIndex(attackers[i] + (fleetflag[i] == 0 ? 0 : 12), Battle.IsFriendCombined, Battle.IsEnemyCombined), - }; - - - for (int k = 0; k < defenders[i].Length; k++) - { - var defender = new PhaseShellingDefender - { - Defender = new BattleIndex(defenders[i][k] + (fleetflag[i] == 0 ? 12 : 0), Battle.IsFriendCombined, Battle.IsEnemyCombined), - CriticalFlag = criticalFlags[i][k], - RawDamage = rawDamages[i][k], - }; - - attack.Defenders.Add(defender); - } - - attack.AttackType = attackTypes[i]; - attack.EquipmentIDs = attackEquipments[i]; - - Attacks.Add(attack); - } - } - - public override bool IsAvailable => (int)RawData.api_hourai_flag[PhaseID - 1] != 0; - - public virtual dynamic ShellingData => RawData["api_hougeki" + Suffix]; - - public override void EmulateBattle(int[] hps, int[] damages) - { - if (!IsAvailable) return; - - foreach (PhaseShellingAttack atk in Attacks) - { - if (atk.AttackTypeTyped.IsSpecialAttack()) - { - List attackers = atk.AttackTypeTyped.SpecialAttackIndexes(); - - for (int i = 0; i < atk.Defenders.Count; i++) - { - var comboatk = new BattleIndex(atk.Attacker.Side, attackers[i]); - BattleDetails.Add(new BattleDayDetail(Battle, comboatk, atk.Defenders[i].Defender, new[] { atk.Defenders[i].RawDamage }, new[] { atk.Defenders[i].CriticalFlag }, atk.AttackType, atk.EquipmentIDs, hps[atk.Defenders[i].Defender])); - AddDamage(hps, atk.Defenders[i].Defender, atk.Defenders[i].Damage); - damages[comboatk] += atk.Defenders[i].Damage; - } - } - else { - foreach (var defs in atk.Defenders.GroupBy(d => d.Defender)) - { - BattleDetails.Add(new BattleDayDetail(Battle, atk.Attacker, defs.Key, defs.Select(d => d.RawDamage).ToArray(), defs.Select(d => d.CriticalFlag).ToArray(), atk.AttackType, atk.EquipmentIDs, hps[defs.Key])); - AddDamage(hps, defs.Key, defs.Sum(d => d.Damage)); - } - damages[atk.Attacker] += atk.Defenders.Sum(d => d.Damage); - } - } - } -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseSupport.cs b/ElectronicObserver/Data/Battle/Phase/PhaseSupport.cs deleted file mode 100644 index 4d3f3a3ef..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseSupport.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 支援攻撃フェーズの処理を行います。 -/// -public class PhaseSupport : PhaseBase -{ - - public readonly bool IsNight; - - public PhaseSupport(BattleData data, string title, bool isNight = false) - : base(data, title) - { - IsNight = isNight; - - switch (SupportFlag) - { - case 1: // 空撃 - case 4: // 対潜 - { - if ((int)SupportData.api_support_airatack.api_stage_flag[2] != 0) - { - // 敵連合でも api_stage3_combined は存在しない? - - Damages = ((double[])SupportData.api_support_airatack.api_stage3.api_edam).ToArray(); - Criticals = ((int[])SupportData.api_support_airatack.api_stage3.api_ecl_flag).ToArray(); - - // 航空戦なので crit フラグが違う - for (int i = 0; i < Criticals.Length; i++) - Criticals[i]++; - } - else - { - Damages = new double[12]; - Criticals = new int[12]; - } - } - break; - case 2: // 砲撃 - case 3: // 雷撃 - { - var dmg = (double[])SupportData.api_support_hourai.api_damage; - var cl = (int[])SupportData.api_support_hourai.api_cl_list; - - Damages = new double[12]; - Array.Copy(dmg, Damages, dmg.Length); - - Criticals = new int[12]; - Array.Copy(cl, Criticals, cl.Length); - } - break; - default: - Damages = new double[12]; - Criticals = new int[12]; - break; - } - } - - - public override bool IsAvailable => SupportFlag != 0; - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) return; - - for (int i = 0; i < Battle.Initial.EnemyMembers.Length; i++) - { - if (Battle.Initial.EnemyMembers[i] > 0) - { - var index = new BattleIndex(BattleSides.EnemyMain, i); - BattleDetails.Add(new BattleSupportDetail(Battle, index, Damages[i], Criticals[i], SupportFlag, hps[index])); - AddDamage(hps, index, (int)Damages[i]); - } - } - if (Battle.IsEnemyCombined) - { - for (int i = 0; i < Battle.Initial.EnemyMembersEscort.Length; i++) - { - if (Battle.Initial.EnemyMembersEscort[i] > 0) - { - var index = new BattleIndex(BattleSides.EnemyEscort, i); - BattleDetails.Add(new BattleSupportDetail(Battle, index, Damages[i + 6], Criticals[i + 6], SupportFlag, hps[index])); - AddDamage(hps, index, (int)Damages[i + 6]); - } - } - } - } - - protected override IEnumerable SearchBattleDetails(int index) - { - return BattleDetails.Where(d => d.DefenderIndex == index); - } - - - /// - /// 支援艦隊フラグ - /// - public int SupportFlag - { - get - { - if (IsNight) - return RawData.api_n_support_flag() ? (int)RawData.api_n_support_flag : 0; - else - return RawData.api_support_flag() ? (int)RawData.api_support_flag : 0; - } - } - - public dynamic SupportData => IsNight ? RawData.api_n_support_info : RawData.api_support_info; - - /// - /// 支援艦隊ID - /// - public int SupportFleetID - { - get - { - switch (SupportFlag) - { - case 1: - case 4: - return (int)SupportData.api_support_airatack.api_deck_id; - - case 2: - case 3: - return (int)SupportData.api_support_hourai.api_deck_id; - - default: - return -1; - - } - } - } - - /// - /// 支援艦隊 - /// - public FleetData SupportFleet - { - get - { - int id = SupportFleetID; - if (id != -1) - return KCDatabase.Instance.Fleet[id]; - else - return null; - } - } - - - /// - /// 与ダメージ [12] - /// - public double[] Damages { get; private set; } - - /// - /// クリティカルフラグ [12] - /// - public int[] Criticals { get; private set; } - - -} diff --git a/ElectronicObserver/Data/Battle/Phase/PhaseTorpedo.cs b/ElectronicObserver/Data/Battle/Phase/PhaseTorpedo.cs deleted file mode 100644 index 6583f2186..000000000 --- a/ElectronicObserver/Data/Battle/Phase/PhaseTorpedo.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElectronicObserver.Data.Battle.Detail; - -namespace ElectronicObserver.Data.Battle.Phase; - -/// -/// 雷撃戦フェーズの処理を行います。 -/// -public class PhaseTorpedo : PhaseBase -{ - - /// - /// フェーズID 0=開幕雷撃, 1-4=雷撃戦 - /// - private readonly int phaseID; - - public PhaseTorpedo(BattleData data, string title, int phaseID) - : base(data, title) - { - - this.phaseID = phaseID; - - if (!IsAvailable) - return; - - Damages = GetConcatArray("api_fdam", "api_edam", 0.0); - - if (IsOpeningTorpedoPhase) - { - AttackDamages = GetConcatArray("api_fydam_list_items", "api_eydam_list_items", null); - Targets = GetConcatArray("api_frai_list_items", "api_erai_list_items", null); - CriticalFlags = GetConcatArray("api_fcl_list_items", "api_ecl_list_items", null); - } - else if (IsClosingTorpedoPhase) - { - AttackDamages = GetConcatArray("api_fydam", "api_eydam", 0).Select(i => new[] { i }).ToArray(); - Targets = GetConcatArray("api_frai", "api_erai", -1).Select(i => new[] { i }).ToArray(); - CriticalFlags = GetConcatArray("api_fcl", "api_ecl", 0).Select(i => new[] { i }).ToArray(); - } - - } - - - public override bool IsAvailable => IsOpeningTorpedoPhase || IsClosingTorpedoPhase; - - private bool IsOpeningTorpedoPhase => phaseID == 0 && (RawData.api_opening_flag() ? (int)RawData.api_opening_flag != 0 : false); - private bool IsClosingTorpedoPhase => phaseID != 0 && ((int)RawData.api_hourai_flag[phaseID - 1] != 0); - - - public override void EmulateBattle(int[] hps, int[] damages) - { - - if (!IsAvailable) - return; - - // 表示上は逐次ダメージ反映のほうが都合がいいが、AddDamage を逐次的にやるとダメコン判定を誤るため - int[] currentHP = new int[hps.Length]; - Array.Copy(hps, currentHP, currentHP.Length); - - for (int i = 0; i < Targets.Length; i++) - { - if (Targets[i] is null) continue; - - for (int j = 0; j < Targets[i].Length; j++) - { - if (Targets[i][j] < 0) continue; - - BattleIndex attacker = new BattleIndex(i, Battle.IsFriendCombined, Battle.IsEnemyCombined); - BattleIndex defender = new BattleIndex(Targets[i][j] + (i < 12 ? 12 : 0), Battle.IsFriendCombined, Battle.IsEnemyCombined); - - BattleDetails.Add(new BattleDayDetail(Battle, attacker, defender, new double[] { AttackDamages[i][j] + Damages[defender] - Math.Floor(Damages[defender]) }, //propagates "guards flagship" flag - new int[] { CriticalFlags[i][j] }, -1, null, currentHP[defender])); - currentHP[defender] -= Math.Max(AttackDamages[i][j], 0); - } - } - - for (int i = 0; i < hps.Length; i++) - { - AddDamage(hps, i, (int)Damages[i]); - damages[i] += AttackDamages[i]?.Sum() ?? 0; - } - - } - - - public dynamic TorpedoData => phaseID == 0 ? RawData.api_opening_atack : RawData.api_raigeki; - - - /// - /// 各艦の被ダメージ - /// - public double[] Damages { get; private set; } - - /// - /// 各艦の与ダメージ - /// - public int[]?[] AttackDamages { get; private set; } - - /// - /// 各艦のターゲットインデックス - /// - public int[]?[] Targets { get; private set; } - - /// - /// クリティカルフラグ(攻撃側) - /// - public int[]?[] CriticalFlags { get; private set; } - - - - - private T[] GetConcatArray(string friendName, string enemyName, T defaultValue) - { - var friend = ConvertToArray(TorpedoData[friendName], 12, defaultValue); - var enemy = ConvertToArray(TorpedoData[enemyName], 12, defaultValue); - - var ret = new T[24]; - - for (int i = 0; i < 12; i++) - { - ret[i] = friend[i]; - ret[i + 12] = enemy[i]; - } - - return ret; - } - - /// - /// 基本的には `(T[])json` と等価ですが、特定の状況下におけるデータエラーを回避するための実装が含まれています - /// https://github.com/andanteyk/ElectronicObserver/issues/294 - /// - private static T[] ConvertToArray(dynamic json, int maxLength, T defaultValue) - { - var ret = Enumerable.Repeat(defaultValue, maxLength).ToArray(); - int i = 0; - foreach (var member in json) - { - ret[i++ % maxLength] = - member is KeyValuePair pair ? (T)pair.Value : - member != null ? (T)member : - default(T); - } - return ret; - } -} diff --git a/ElectronicObserver/Data/Constants.cs b/ElectronicObserver/Data/Constants.cs index a8f673781..40e13e676 100644 --- a/ElectronicObserver/Data/Constants.cs +++ b/ElectronicObserver/Data/Constants.cs @@ -630,34 +630,20 @@ public static int GetFormation(string value) /// /// 陣形を表す文字列(短縮版)を取得します。 /// - public static string GetFormationShort(int id) + public static string GetFormationShort(FormationType formationType) => formationType switch { - switch (id) - { - case 1: - return ConstantsRes.LineAheadShort; - case 2: - return ConstantsRes.DoubleLineShort; - case 3: - return ConstantsRes.DiamondShort; - case 4: - return ConstantsRes.EchelonShort; - case 5: - return ConstantsRes.LineAbreastShort; - case 6: - return ConstantsRes.VanguardShort; - case 11: - return ConstantsRes.FirstPatrolFormationShort; - case 12: - return ConstantsRes.SecondPatrolFormationShort; - case 13: - return ConstantsRes.ThirdPatrolFormationShort; - case 14: - return ConstantsRes.FourthPatrolFormationShort; - default: - return ConstantsRes.Unknown; - } - } + FormationType.LineAhead => ConstantsRes.LineAheadShort, + FormationType.DoubleLine => ConstantsRes.DoubleLineShort, + FormationType.Diamond => ConstantsRes.DiamondShort, + FormationType.Echelon => ConstantsRes.EchelonShort, + FormationType.LineAbreast => ConstantsRes.LineAbreastShort, + FormationType.Vanguard => ConstantsRes.VanguardShort, + FormationType.FirstPatrolFormation => ConstantsRes.FirstPatrolFormationShort, + FormationType.SecondPatrolFormation=> ConstantsRes.SecondPatrolFormationShort, + FormationType.ThirdPatrolFormation => ConstantsRes.ThirdPatrolFormationShort, + FormationType.FourthPatrolFormation => ConstantsRes.FourthPatrolFormationShort, + _ => ConstantsRes.Unknown, + }; /// /// 交戦形態を表す文字列を取得します。 @@ -718,31 +704,16 @@ public static string GetEngagementFormShort(int id) /// /// 索敵結果を表す文字列(短縮版)を取得します。 /// - public static string GetSearchingResultShort(int id) + public static string GetSearchingResultShort(DetectionType id) => id switch { - switch (id) - { - case 1: - return ConstantsRes.Success; - case 2: - return ConstantsRes.Success + "△"; - case 3: - return ConstantsRes.NoReturn; - case 4: - return ConstantsRes.Failure; - case 5: - return ConstantsRes.Success; - case 6: - return ConstantsRes.Failure; - default: - return ConstantsRes.Unknown; - } - } - - /// - /// 制空戦の結果を表す文字列を取得します。 - /// - public static string GetAirSuperiority(int id) => GetAirSuperiority((AirState)id); + DetectionType.Success => ConstantsRes.Success, + DetectionType.SuccessNoReturn => ConstantsRes.Success + "△", + DetectionType.NoReturn => ConstantsRes.NoReturn, + DetectionType.Failure => ConstantsRes.Failure, + DetectionType.SuccessNoPlane => ConstantsRes.Success, + DetectionType.FailureNoPlane => ConstantsRes.Failure, + _ => ConstantsRes.Unknown, + }; /// /// 制空戦の結果を表す文字列を取得します。 diff --git a/ElectronicObserver/Data/FleetManager.cs b/ElectronicObserver/Data/FleetManager.cs index bef86af65..e21870ffe 100644 --- a/ElectronicObserver/Data/FleetManager.cs +++ b/ElectronicObserver/Data/FleetManager.cs @@ -97,10 +97,10 @@ public override void LoadFromResponse(string apiname, dynamic data) { int index = ii - 1; - if (index < battle.FirstBattle.Initial.FriendFleet.Members.Count) - battle.FirstBattle.Initial.FriendFleet.Escape(index); + if (index < battle.FirstBattle.FleetsBeforeBattle.Fleet.Members.Count) + battle.FirstBattle.FleetsBeforeBattle.Fleet.Escape(index); else - battle.FirstBattle.Initial.FriendFleetEscort.Escape(index - 6); + battle.FirstBattle.FleetsBeforeBattle.EscortFleet!.Escape(index - 6); } } break; diff --git a/ElectronicObserver/Data/Quest/QuestProgressManager.cs b/ElectronicObserver/Data/Quest/QuestProgressManager.cs index eae81e8fb..d79f7c497 100644 --- a/ElectronicObserver/Data/Quest/QuestProgressManager.cs +++ b/ElectronicObserver/Data/Quest/QuestProgressManager.cs @@ -1286,7 +1286,7 @@ void BattleFinished(string apiname, dynamic data) var bm = KCDatabase.Instance.Battle; var battle = bm.SecondBattle ?? bm.FirstBattle; - var hps = battle.ResultHPs; + var hps = battle.ResultHPs.ToList(); if (hps == null) return; @@ -1304,17 +1304,17 @@ void BattleFinished(string apiname, dynamic data) continue; foreach (var p in slaughterList) - p.Increment(ship.ShipType); + p.Increment(ship.MasterShip.ShipType); } if (bm.IsEnemyCombined && hps[Battle.BattleIndex.Get(Battle.BattleSides.EnemyEscort, i)] <= 0) { - var ship = battle.Initial.EnemyMembersEscortInstance[i]; + var ship = battle.Initial.EnemyMembersEscortInstance?[i]; if (ship == null) continue; foreach (var p in slaughterList) - p.Increment(ship.ShipType); + p.Increment(ship.MasterShip.ShipType); } } diff --git a/ElectronicObserver/Data/TsunDbSubmission/Battle/TsunDbBattleData.cs b/ElectronicObserver/Data/TsunDbSubmission/Battle/TsunDbBattleData.cs index c35d85fd4..e316f94ab 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/Battle/TsunDbBattleData.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/Battle/TsunDbBattleData.cs @@ -93,7 +93,7 @@ public TsunDbBattleData(string apiName, dynamic rawApi) Fleet = new TsunDbFleetsAndAirBaseData(); ResupplyUsed = Database.Battle.ResupplyUsed; - Formation = Database.Battle.FirstBattle.Searching.FormationFriend; + Formation = (int)Database.Battle.FirstBattle.Searching.PlayerFormationType; AmountOfNodes = TsunDbSubmissionManager.CurrentMapAmountOfNodes; RawApi = JsonSerializer.Deserialize(rawApi.ToString()); diff --git a/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs b/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs index e266b0ce6..f97fd4b54 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using ElectronicObserver.Data.Battle.Phase; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Data.TsunDbSubmission; @@ -20,7 +20,7 @@ public class EnemyComp : TsunDbEntity public List HP { get; private set; } = new(); [JsonPropertyName("stats")] - public List Stats { get; private set; } = new(); + public List> Stats { get; private set; } = new(); [JsonPropertyName("equip")] public List Equips { get; private set; } = new(); @@ -52,7 +52,7 @@ public class EnemyComp : TsunDbEntity public List? HPEscort { get; private set; } [JsonPropertyName("statsEscort")] - public List? StatsEscort { get; private set; } + public List>? StatsEscort { get; private set; } [JsonPropertyName("equipEscort")] public List? EquipsEscort { get; private set; } @@ -69,7 +69,7 @@ public void PrepareEnemyCompFromCurrentState() HP = initial.EnemyMaxHPs.Take(shipCount).ToList(); Stats = initial.EnemyParameters.Take(shipCount).ToList(); Equips = initial.EnemySlots.Take(shipCount).ToList(); - Formation = db.Battle.FirstBattle.Searching.FormationEnemy; + Formation = (int)db.Battle.FirstBattle.Searching.EnemyFormationType; // If this is an event map if (db.Battle.Compass.MapAreaID > 30) diff --git a/ElectronicObserver/Data/TsunDbSubmission/ShipDrop.cs b/ElectronicObserver/Data/TsunDbSubmission/ShipDrop.cs index c8913ef7c..488cc49b6 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/ShipDrop.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/ShipDrop.cs @@ -67,7 +67,7 @@ private void PrepareDropData(dynamic apidata) HqLvl = db.Admiral.Level; Difficulty = mapInfoData.EventDifficulty > 0 ? mapInfoData.EventDifficulty : 0; - Ship = db.Battle.Result.DroppedShipID > 0 ? db.Battle.Result.DroppedShipID : -1; + Ship = db.Battle.Result.DroppedShipId > 0 ? (int)db.Battle.Result.DroppedShipId : -1; PrepareEnemyCompData(apidata); } diff --git a/ElectronicObserver/Data/TsunDbSubmission/ShipDropLoc.cs b/ElectronicObserver/Data/TsunDbSubmission/ShipDropLoc.cs index 9874d7a4e..fc74c5e93 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/ShipDropLoc.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/ShipDropLoc.cs @@ -50,6 +50,6 @@ private void PrepareDropData(dynamic apidata) } Difficulty = mapInfoData.EventDifficulty > 0 ? mapInfoData.EventDifficulty : 0; - Ship = db.Battle.Result.DroppedShipID > 0 ? db.Battle.Result.DroppedShipID : -1; + Ship = db.Battle.Result.DroppedShipId > 0 ? (int)db.Battle.Result.DroppedShipId : -1; } } diff --git a/ElectronicObserver/Notifier/NotifierDamage.cs b/ElectronicObserver/Notifier/NotifierDamage.cs index 90965da60..96c9b3d3c 100644 --- a/ElectronicObserver/Notifier/NotifierDamage.cs +++ b/ElectronicObserver/Notifier/NotifierDamage.cs @@ -182,10 +182,10 @@ private void CheckBattle() var list = new List(); var battle = bm.SecondBattle ?? bm.FirstBattle; - list.AddRange(GetDamagedShips(battle.Initial.FriendFleet, battle.ResultHPs.ToArray())); + list.AddRange(GetDamagedShips(battle.FleetsBeforeBattle.Fleet, battle.ResultHPs.ToArray())); if (bm.IsCombinedBattle) - list.AddRange(GetDamagedShips(battle.Initial.FriendFleetEscort, battle.ResultHPs.Skip(6).ToArray())); + list.AddRange(GetDamagedShips(battle.FleetsBeforeBattle.EscortFleet!, battle.ResultHPs.Skip(6).ToArray())); if (list.Count > 0) @@ -211,7 +211,7 @@ private string[] GetDamagedShips(IEnumerable ships) return ships.Where(s => IsShipDamaged(s, s?.HPCurrent ?? 0)).Select(s => $"{s.NameWithLevel} ({s.HPCurrent}/{s.HPMax})").ToArray(); } - private string[] GetDamagedShips(FleetData fleet, int[] hps) + private string[] GetDamagedShips(IFleetData fleet, int[] hps) { LinkedList list = new LinkedList(); diff --git a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs index 595f7fabe..6314d1ad5 100644 --- a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs +++ b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs @@ -187,9 +187,9 @@ public static EnemyFleetElement CreateFromCurrentState() battle.Compass.MapInfoID, battle.IsBaseAirRaid ? -1 : battle.Compass.CellId, battle.Compass.MapInfo.EventDifficulty, - battle.FirstBattle.Searching.FormationEnemy, - battle.IsEnemyCombined ? initial.EnemyMembers.Take(6).Concat(initial.EnemyMembersEscort).ToArray() : initial.EnemyMembers, - battle.IsEnemyCombined ? initial.EnemyLevels.Take(6).Concat(initial.EnemyLevelsEscort).ToArray() : initial.EnemyLevels, + (int)battle.FirstBattle.Searching.EnemyFormationType, + battle.IsEnemyCombined ? initial.EnemyMembers.Take(6).Concat(initial.EnemyMembersEscort).ToArray() : initial.EnemyMembers.ToArray(), + battle.IsEnemyCombined ? initial.EnemyLevels.Take(6).Concat(initial.EnemyLevelsEscort).ToArray() : initial.EnemyLevels.ToArray(), baseExp); } diff --git a/ElectronicObserver/Resource/Record/ShipParameterRecord.cs b/ElectronicObserver/Resource/Record/ShipParameterRecord.cs index b8bc5e701..710ee9621 100644 --- a/ElectronicObserver/Resource/Record/ShipParameterRecord.cs +++ b/ElectronicObserver/Resource/Record/ShipParameterRecord.cs @@ -6,6 +6,8 @@ using ElectronicObserver.Data; using ElectronicObserver.Data.Battle; using ElectronicObserver.Observer; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserverTypes; namespace ElectronicObserver.Resource.Record; @@ -1086,25 +1088,26 @@ void UpdateParams(int id, int maxhp, int[] status, int[] slot) Update(param); } - - for (int i = 0; i < binit.EnemyMembers.Length; i++) + int[] enemyMembers = binit.EnemyMembers.ToArray(); + for (int i = 0; i < enemyMembers.Length; i++) { - int id = binit.EnemyMembers[i]; + int id = enemyMembers[i]; if (id <= 0) continue; - UpdateParams(id, binit.EnemyMaxHPs[i], binit.EnemyParameters?[i], binit.EnemySlots[i]); + UpdateParams(id, binit.EnemyMaxHPs[i], binit.EnemyParameters?[i].ToArray(), binit.EnemySlots[i]); } if (battle.IsEnemyCombined) { - for (int i = 0; i < binit.EnemyMembersEscort.Length; i++) + int[] enemyMembersEscort = binit.EnemyMembersEscort!.ToArray(); + for (int i = 0; i < enemyMembersEscort.Length; i++) { - int id = binit.EnemyMembersEscort[i]; + int id = enemyMembersEscort[i]; if (id <= 0) continue; - UpdateParams(id, binit.EnemyMaxHPsEscort[i], binit.EnemyParametersEscort?[i], binit.EnemySlotsEscort[i]); + UpdateParams(id, binit.EnemyMaxHPsEscort[i], binit.EnemyParametersEscort?[i].ToArray(), binit.EnemySlotsEscort[i]); } } @@ -1115,7 +1118,7 @@ void EstimateUnknownAircraftSlot() var db = KCDatabase.Instance; // 航空戦が存在するときだけ処理する - if (!(battle is BattleDay battleDay)) + if (!(battle is FirstBattleData battleDay)) return; @@ -1125,7 +1128,7 @@ void EstimateUnknownAircraftSlot() members = members.Concat(binit.EnemyMembersEscort); - void checkNoAircraft(int id, int[] eqs) + void CheckNoAircraft(int id, int[] eqs) { if (id <= 0 || this[id].Aircraft != null) @@ -1139,12 +1142,12 @@ void checkNoAircraft(int id, int[] eqs) } for (int i = 0; i < binit.EnemyMembers.Length; i++) - checkNoAircraft(binit.EnemyMembers[i], binit.EnemySlots[i]); + CheckNoAircraft(binit.EnemyMembers[i], binit.EnemySlots[i]); if (battleDay.IsEnemyCombined) { for (int i = 0; i < binit.EnemyMembersEscort.Length; i++) - checkNoAircraft(binit.EnemyMembersEscort[i], binit.EnemySlotsEscort[i]); + CheckNoAircraft(binit.EnemyMembersEscort[i], binit.EnemySlotsEscort[i]); } @@ -1173,7 +1176,7 @@ void checkNoAircraft(int id, int[] eqs) } - void estimate(int actualAircraftCount, Func isAircraft) + void Estimate(int actualAircraftCount, Func isAircraft) { if (unknownShipEquipment.Select(id => db.MasterEquipments[id]).Count(isAircraft) != 1) return; @@ -1215,22 +1218,21 @@ int getAircraftCount(int shipID, int[] equipmentIDs, int[] aircraft) } } - - if (battleDay.BaseAirAttack?.IsAvailable ?? false) + if (battleDay is IBaseAirAttack { BaseAirAttack: { } baseAirAttack }) { - var firstUnit = battleDay.BaseAirAttack.AirAttackUnits.FirstOrDefault(); + var firstUnit = baseAirAttack.Units.FirstOrDefault(); if (!firstUnit?.IsStage1Available ?? false) return; - estimate(firstUnit.AircraftTotalStage1Enemy, eq => eq?.IsAircraft ?? false); + Estimate(firstUnit.AircraftTotalStage1Enemy, eq => eq?.IsAircraft ?? false); } - else if (battleDay.AirBattle?.IsStage1Available ?? false) + else if (battleDay is IAirBattle { AirBattle: { } airBattle }) { - estimate(battleDay.AirBattle.AircraftTotalStage1Enemy, eq => eq?.IsCombatAircraft ?? false); + Estimate(airBattle.AircraftTotalStage1Enemy, eq => eq?.IsCombatAircraft ?? false); } - else if (battleDay is BattleBaseAirRaid battleAirRaid && (battleAirRaid.BaseAirRaid?.IsStage1Available ?? false)) + else if (battleDay is BattleBaseAirRaid battleAirRaid && (battleAirRaid.BaseAirRaid is not null)) { - estimate(battleAirRaid.BaseAirRaid.AircraftTotalStage1Enemy, eq => eq?.IsCombatAircraft ?? false); + Estimate(battleAirRaid.BaseAirRaid.AircraftTotalStage1Enemy, eq => eq?.IsCombatAircraft ?? false); } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs index e7b580489..e31870282 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs @@ -587,17 +587,17 @@ void ProcessData(IFleetData fleet, IFleetData attackerFleet, FleetFlag fleetFlag AirBaseSquadron4Aircraft = airAttackUnit.Squadrons.Skip(3).FirstOrDefault()?.AircraftCount, Stage1 = new() { - PlayerAircraftTotal = airAttackUnit.Stage1FCount, - PlayerAircraftLost = airAttackUnit.Stage1FLostcount, - EnemyAircraftTotal = airAttackUnit.Stage1ECount, - EnemyAircraftLost = airAttackUnit.Stage1ELostcount, + PlayerAircraftTotal = airAttackUnit.AircraftTotalStage1Friend, + PlayerAircraftLost = airAttackUnit.AircraftLostStage1Friend, + EnemyAircraftTotal = airAttackUnit.AircraftTotalStage1Enemy, + EnemyAircraftLost = airAttackUnit.AircraftLostStage1Enemy, }, Stage2 = new() { - PlayerAircraftTotal = airAttackUnit.Stage2FCount, - PlayerAircraftLost = airAttackUnit.Stage2FLostcount, - EnemyAircraftTotal = airAttackUnit.Stage2ECount, - EnemyAircraftLost = airAttackUnit.Stage2ELostcount, + PlayerAircraftTotal = airAttackUnit.AircraftTotalStage2Friend, + PlayerAircraftLost = airAttackUnit.AircraftLostStage2Friend, + EnemyAircraftTotal = airAttackUnit.AircraftTotalStage2Enemy, + EnemyAircraftLost = airAttackUnit.AircraftLostStage2Enemy, }, Attacker1 = MakeShip(attackerFleet.MembersWithoutEscaped?.Skip(0).FirstOrDefault()), Attacker2 = MakeShip(attackerFleet.MembersWithoutEscaped?.Skip(1).FirstOrDefault()), @@ -700,10 +700,10 @@ private static List AirBaseAirDefense( EnemyFormation = Constants.GetFormation(searching.EnemyFormationType), Engagement = Constants.GetEngagementForm(searching.EngagementType), AirBaseDamage = GetAirBaseDamage(airBaseRaid.ApiLostKind), - PlayerAircraft = airBaseRaid.Stage1FCount, - PlayerAircraftLost = airBaseRaid.Stage1FLostcount, - EnemyAircraft = airBaseRaid.Stage1ECount, - EnemyAircraftLost = airBaseRaid.Stage1ELostcount, + PlayerAircraft = airBaseRaid.AircraftTotalStage1Friend, + PlayerAircraftLost = airBaseRaid.AircraftLostStage1Friend, + EnemyAircraft = airBaseRaid.AircraftTotalStage1Enemy, + EnemyAircraftLost = airBaseRaid.AircraftLostStage1Enemy, AirState = GetAirState(airBaseRaid), PlayerContact = airBaseRaid.TouchAircraftFriend ?? "なし", EnemyContact = airBaseRaid.TouchAircraftEnemy ?? "なし", @@ -777,17 +777,17 @@ private static AirBattleExportModel MakeAirBattleExport(BattleNode node, CommonData = MakeCommonData(node, IsFirstNode(sortieDetail.Nodes, node), sortieDetail, admiralLevel, airBattle, searching), Stage1 = new() { - PlayerAircraftTotal = airBattle.Stage1FCount, - PlayerAircraftLost = airBattle.Stage1FLostcount, - EnemyAircraftTotal = airBattle.Stage1ECount, - EnemyAircraftLost = airBattle.Stage1ELostcount, + PlayerAircraftTotal = airBattle.AircraftTotalStage1Friend, + PlayerAircraftLost = airBattle.AircraftLostStage1Friend, + EnemyAircraftTotal = airBattle.AircraftTotalStage1Enemy, + EnemyAircraftLost = airBattle.AircraftLostStage1Enemy, }, Stage2 = new() { - PlayerAircraftTotal = airBattle.Stage2FCount, - PlayerAircraftLost = airBattle.Stage2FLostcount, - EnemyAircraftTotal = airBattle.Stage2ECount, - EnemyAircraftLost = airBattle.Stage2ELostcount, + PlayerAircraftTotal = airBattle.AircraftTotalStage2Friend, + PlayerAircraftLost = airBattle.AircraftLostStage2Friend, + EnemyAircraftTotal = airBattle.AircraftTotalStage2Enemy, + EnemyAircraftLost = airBattle.AircraftLostStage2Enemy, }, AntiAirCutIn = new() { @@ -911,7 +911,7 @@ private static CommonDataExportModel MakeCommonData(BattleNode node, bool isFirs (true, _) => CsvExportResources.BossNode, _ => "", }, - Rank = WinRank(node.BattleResult?.WinRank), + Rank = WinRank(node.BattleResult?.Rank), EnemyFleet = node.BattleResult?.EnemyFleetName, AdmiralLevel = admiralLevel, PlayerFormation = Constants.GetFormation(searching.PlayerFormationType), diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/AirBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/AirBattleData.cs index ff8045d19..4c3faeff1 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/AirBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/AirBattleData.cs @@ -1,16 +1,17 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; -public abstract class AirBattleData : FirstBattleData +public abstract class AirBattleData : FirstBattleData, IBaseAirAttack, IAirBattle { protected PhaseJetBaseAirAttack? JetBaseAirAttack { get; } - protected PhaseJetAirBattle? JetAirBattle { get; } - protected PhaseBaseAirAttack? BaseAirAttack { get; } + public PhaseJetAirBattle? JetAirBattle { get; } + public PhaseBaseAirAttack? BaseAirAttack { get; } protected PhaseFriendlySupportInfo? FriendlySupportInfo { get; } protected PhaseFriendlyAirBattle? FriendlyAirBattle { get; } - protected PhaseAirBattle? AirBattle { get; } + public PhaseAirBattle? AirBattle { get; } protected AirBattleData(PhaseFactory phaseFactory, BattleFleets fleets, IAirBattleApiResponse battle, bool isMultiAirBattle = false) : base(phaseFactory, fleets, battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleAirBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleAirBattle.cs index 6059a14f2..ee25a5d76 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleAirBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleAirBattle.cs @@ -14,7 +14,7 @@ public sealed class BattleAirBattle : AirBattleData public override string Title => ConstantsRes.Title_NormalFleetAirBattle; private PhaseSupport? Support { get; } - private PhaseAirBattle? AirBattle2 { get; } + public PhaseAirBattle? AirBattle2 { get; } public BattleAirBattle(PhaseFactory phaseFactory, BattleFleets fleets, ApiReqSortieAirbattleResponse battle) : base(phaseFactory, fleets, battle, true) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleBaseAirRaid.cs index b20c9ecbd..2622be07f 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleBaseAirRaid.cs @@ -12,7 +12,7 @@ public sealed class BattleBaseAirRaid : FirstBattleData { public override string Title => ConstantsRes.Title_BaseAirRaid; - private PhaseBaseAirRaid? BaseAirRaid { get; } + public PhaseBaseAirRaid? BaseAirRaid { get; } public BattleBaseAirRaid(PhaseFactory phaseFactory, BattleFleets fleets, ApiDestructionBattle battle) : base(phaseFactory, fleets, battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleCombinedAirBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleCombinedAirBattle.cs index bef3594db..cf008aff3 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleCombinedAirBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleCombinedAirBattle.cs @@ -13,7 +13,7 @@ public sealed class BattleCombinedAirBattle : AirBattleData public override string Title => ConstantsRes.Title_NormalFleetAirBattle; private PhaseSupport? Support { get; } - private PhaseAirBattle? AirBattle2 { get; } + public PhaseAirBattle? AirBattle2 { get; } public BattleCombinedAirBattle(PhaseFactory phaseFactory, BattleFleets fleets, ApiReqCombinedBattleAirbattleResponse battle) : base(phaseFactory, fleets, battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index 459ff736a..66e92cea8 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -14,7 +14,16 @@ public abstract class BattleData protected PhaseFactory PhaseFactory { get; } public BattleFleets FleetsBeforeBattle => Initial.FleetsAfterPhase!; - public BattleFleets FleetsAfterBattle { get; protected set; } + public BattleFleets FleetsAfterBattle { get; private set; } + + public bool IsPractice => this is BattlePracticeDay or BattlePracticeNight; + public bool IsFriendCombined => FleetsBeforeBattle.EscortFleet is not null; + public bool IsEnemyCombined => FleetsBeforeBattle.EnemyEscortFleet is not null; + public bool IsBaseAirRaid => this is BattleBaseAirRaid; + + public IEnumerable ResultHPs => FleetsAfterBattle + .SortieShips() + .Select(s => s?.HPCurrent ?? 0); public IEnumerable AirBaseBeforeAfter => FleetsBeforeBattle.AirBases .Zip(FleetsAfterBattle.AirBases, (before, after) => (Before: before, After: after)) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattlePracticeDay.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattlePracticeDay.cs index d868f82c7..6fd2ee6d1 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattlePracticeDay.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattlePracticeDay.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using ElectronicObserver.KancolleApi.Types.ApiReqPractice.Battle; using ElectronicObserver.KancolleApi.Types.Legacy.OpeningTorpedoRework; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; @@ -9,12 +10,12 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; /// 演習 昼戦
/// api_req_practice/battle ///
-public sealed class BattlePracticeDay : FirstBattleData +public sealed class BattlePracticeDay : FirstBattleData, IAirBattle { public override string Title => ConstantsRes.Title_PracticeDay; - private PhaseJetAirBattle? JetAirBattle { get; } - private PhaseAirBattle? AirBattle { get; } + public PhaseJetAirBattle? JetAirBattle { get; } + public PhaseAirBattle? AirBattle { get; } private PhaseOpeningAsw? OpeningAsw { get; } private PhaseOpeningTorpedo? OpeningTorpedo { get; } private PhaseShelling? Shelling1 { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayBattleData.cs index 420ee4413..ad3a9fdfc 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayBattleData.cs @@ -6,7 +6,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; public abstract class DayBattleData : AirBattleData { - protected PhaseSupport? Support { get; } + public PhaseSupport? Support { get; } protected PhaseOpeningAsw? OpeningAsw { get; } protected PhaseOpeningTorpedo? OpeningTorpedo { get; } protected PhaseShelling? Shelling1 { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayFromNightBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayFromNightBattleData.cs index 1ff84a204..fd0a4db40 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayFromNightBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/DayFromNightBattleData.cs @@ -1,18 +1,21 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.KancolleApi.Types.Legacy.OpeningTorpedoRework; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; -public abstract class DayFromNightBattleData : NightOnlyBattleData +public abstract class DayFromNightBattleData : NightOnlyBattleData, IBaseAirAttack, IAirBattle { + public bool NextToDay { get; } + protected PhaseNightBattle? NightBattle { get; } protected PhaseNightBattle? NightBattle2 { get; } protected PhaseJetBaseAirAttack? JetBaseAirAttack { get; } - protected PhaseJetAirBattle? JetAirBattle { get; } - protected PhaseBaseAirAttack? BaseAirAttack { get; } - protected PhaseAirBattle? AirBattle { get; } - protected PhaseSupport? Support { get; } + public PhaseJetAirBattle? JetAirBattle { get; } + public PhaseBaseAirAttack? BaseAirAttack { get; } + public PhaseAirBattle? AirBattle { get; } + public PhaseSupport? Support { get; } protected PhaseOpeningAsw? OpeningAsw { get; } protected PhaseOpeningTorpedo? OpeningTorpedo { get; } protected PhaseShelling? Shelling1 { get; } @@ -22,6 +25,8 @@ public abstract class DayFromNightBattleData : NightOnlyBattleData protected DayFromNightBattleData(PhaseFactory phaseFactory, BattleFleets fleets, IDayFromNightBattleApiResponse battle) : base(phaseFactory, fleets, battle) { + NextToDay = battle.ApiDayFlag != 0; + NightBattle = PhaseFactory.NightBattle(battle.ApiNHougeki1); NightBattle2 = PhaseFactory.NightBattle(battle.ApiNHougeki2); JetBaseAirAttack = PhaseFactory.JetBaseAirAttack(battle.ApiAirBaseInjection); @@ -39,6 +44,8 @@ protected DayFromNightBattleData(PhaseFactory phaseFactory, BattleFleets fleets, protected DayFromNightBattleData(PhaseFactory phaseFactory, BattleFleets fleets, IOpeningTorpedoRework_DayFromNightBattleApiResponse battle) : base(phaseFactory, fleets, battle) { + NextToDay = battle.ApiDayFlag != 0; + NightBattle = PhaseFactory.NightBattle(battle.ApiNHougeki1); NightBattle2 = PhaseFactory.NightBattle(battle.ApiNHougeki2); JetBaseAirAttack = PhaseFactory.JetBaseAirAttack(battle.ApiAirBaseInjection); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/FirstBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/FirstBattleData.cs index 6df5e4d4b..8f4294644 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/FirstBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/FirstBattleData.cs @@ -5,7 +5,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; public abstract class FirstBattleData : BattleData { - protected PhaseSearching Searching { get; } + public PhaseSearching Searching { get; } protected FirstBattleData(PhaseFactory phaseFactory, BattleFleets fleets, IFirstBattleApiResponse battle) : base(phaseFactory, fleets, battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IAirBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IAirBattle.cs new file mode 100644 index 000000000..81310a4b0 --- /dev/null +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IAirBattle.cs @@ -0,0 +1,9 @@ +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; + +namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; + +public interface IAirBattle +{ + PhaseJetAirBattle? JetAirBattle { get; } + PhaseAirBattle? AirBattle { get; } +} diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IBaseAirAttack.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IBaseAirAttack.cs new file mode 100644 index 000000000..900f64b98 --- /dev/null +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IBaseAirAttack.cs @@ -0,0 +1,8 @@ +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; + +namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; + +public interface IBaseAirAttack +{ + PhaseBaseAirAttack? BaseAirAttack { get; } +} diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/INightInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/INightInitial.cs new file mode 100644 index 000000000..accb56567 --- /dev/null +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/INightInitial.cs @@ -0,0 +1,8 @@ +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; + +namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; + +public interface INightInitial +{ + PhaseNightInitial? NightInitial { get; } +} diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IPhaseAirBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IPhaseAirBattle.cs new file mode 100644 index 000000000..72d4953a6 --- /dev/null +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Interfaces/IPhaseAirBattle.cs @@ -0,0 +1,29 @@ +using ElectronicObserverTypes; + +namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; + +public interface IPhaseAirBattle +{ + bool IsStage1Available { get; } + bool IsStage2Available { get; } + + int AircraftLostStage1Friend { get; } + int AircraftTotalStage1Friend { get; } + int AircraftLostStage1Enemy { get; } + int AircraftTotalStage1Enemy { get; } + + int AircraftLostStage2Friend { get; } + int AircraftTotalStage2Friend { get; } + int AircraftLostStage2Enemy { get; } + int AircraftTotalStage2Enemy { get; } + + string? TouchAircraftFriend { get; } + string? TouchAircraftEnemy { get; } + + AirState AirState { get; } + + bool IsAACutinAvailable { get; } + int AACutInIndex { get; } + string? AACutInShipName { get; } + int AACutInKind { get; } +} diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightBattleData.cs index 6ecf74871..ef98883aa 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightBattleData.cs @@ -1,11 +1,12 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; -public abstract class NightBattleData : FirstBattleData +public abstract class NightBattleData : FirstBattleData, INightInitial { - protected PhaseNightInitial? NightInitial { get; } + public PhaseNightInitial? NightInitial { get; } protected PhaseFriendlySupportInfo? FriendlySupportInfo { get; } protected PhaseFriendlyShelling? FriendlyShelling { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightOnlyBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightOnlyBattleData.cs index d83c23659..325c88a64 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightOnlyBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/NightOnlyBattleData.cs @@ -5,7 +5,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; public abstract class NightOnlyBattleData : NightBattleData { - protected PhaseSupport? NightSupport { get; } + public PhaseSupport? NightSupport { get; } protected NightOnlyBattleData(PhaseFactory phaseFactory, BattleFleets fleets, INightBattleApiResponse battle) : base(phaseFactory, fleets, battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs index 6767552d1..a01eea686 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Models; using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.KancolleApi.Types.Models; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Wpf; using ElectronicObserverTypes; using ElectronicObserverTypes.AntiAir; @@ -11,7 +13,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseAirBattleBase : PhaseBase +public class PhaseAirBattleBase : PhaseBase, IPhaseAirBattle { public override string Title => BattleRes.BattlePhaseAirBattle; @@ -24,27 +26,44 @@ public class PhaseAirBattleBase : PhaseBase public AirState AirState { get; } - public int Stage1FLostcount { get; } - public int Stage1FCount { get; } - public int Stage1ELostcount { get; } - public int Stage1ECount { get; } + public int AircraftLostStage1Friend { get; } + public int AircraftTotalStage1Friend { get; } + public int AircraftLostStage1Enemy { get; } + public int AircraftTotalStage1Enemy { get; } - public int Stage2FLostcount { get; private set; } - public int Stage2FCount { get; private set; } - public int Stage2ELostcount { get; private set; } - public int Stage2ECount { get; private set; } + public int AircraftLostStage2Friend { get; private set; } + public int AircraftTotalStage2Friend { get; private set; } + public int AircraftLostStage2Enemy { get; private set; } + public int AircraftTotalStage2Enemy { get; private set; } + + [MemberNotNullWhen(true, nameof(ApiAirFire))] + public bool IsAACutinAvailable => ApiAirFire is not null; + + public int AACutInIndex => ApiAirFire?.ApiIdx ?? -1; + public string? AACutInShipName => IsAACutinAvailable switch + { + true => FleetsAfterPhase?.GetShip(new(ApiAirFire.ApiIdx, FleetFlag.Player))?.NameWithLevel, + _ => null, + }; + public int AACutInKind => ApiAirFire?.ApiKind ?? -1; /// /// AACI /// public ApiAirFire? ApiAirFire { get; private set; } + [MemberNotNullWhen(true, nameof(Stage1))] + public bool IsStage1Available => Stage1 is not null; + private ApiStage1? Stage1 => AirBattleData switch { IApiAirBattle aab => aab.ApiStage1, _ => null, }; + [MemberNotNullWhen(true, nameof(Stage2))] + public bool IsStage2Available => Stage2 is not null; + private ApiStage2? Stage2 => AirBattleData switch { IApiAirBattle aab => aab.ApiStage2, @@ -93,7 +112,7 @@ public class PhaseAirBattleBase : PhaseBase public string? TouchAircraftFriend => Stage1?.ApiTouchPlane switch { - [EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, + [EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, _ => null, }; public string? TouchAircraftFriendDisplay => TouchAircraftFriend switch @@ -104,7 +123,7 @@ public class PhaseAirBattleBase : PhaseBase public string? TouchAircraftEnemy => Stage1?.ApiTouchPlane switch { - [_, EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, + [_, EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, _ => null, }; public string? TouchAircraftEnemyDisplay => TouchAircraftEnemy switch @@ -124,18 +143,18 @@ protected PhaseAirBattleBase(IKCDatabase kcDatabase, IApiAirBattle airBattleData if (airBattleData.ApiStage1 is not null) { AirState = airBattleData.ApiStage1.ApiDispSeiku; - Stage1FLostcount = airBattleData.ApiStage1.ApiFLostcount; - Stage1FCount = airBattleData.ApiStage1.ApiFCount; - Stage1ELostcount = airBattleData.ApiStage1.ApiELostcount; - Stage1ECount = airBattleData.ApiStage1.ApiECount; + AircraftLostStage1Friend = airBattleData.ApiStage1.ApiFLostcount; + AircraftTotalStage1Friend = airBattleData.ApiStage1.ApiFCount; + AircraftLostStage1Enemy = airBattleData.ApiStage1.ApiELostcount; + AircraftTotalStage1Enemy = airBattleData.ApiStage1.ApiECount; Stage1Display = GetStage1Display ( AirState, - Stage1FLostcount, - Stage1FCount, - Stage1ELostcount, - Stage1ECount + AircraftLostStage1Friend, + AircraftTotalStage1Friend, + AircraftLostStage1Enemy, + AircraftTotalStage1Enemy ); } @@ -143,26 +162,27 @@ protected PhaseAirBattleBase(IKCDatabase kcDatabase, IApiAirBattle airBattleData LaunchedShipIndexEnemy = GetLaunchedShipIndex(airBattleData.ApiPlaneFrom, 1); } - protected PhaseAirBattleBase(IApiJetAirBattle airBattleData, int waveIndex = 0) + protected PhaseAirBattleBase(IKCDatabase kcDatabase, IApiJetAirBattle airBattleData, int waveIndex = 0) { + KcDatabase = kcDatabase; AirBattleData = airBattleData; WaveIndex = waveIndex; if (airBattleData.ApiStage1 is not null) { AirState = AirState.Unknown; - Stage1FLostcount = airBattleData.ApiStage1.ApiFLostcount; - Stage1FCount = airBattleData.ApiStage1.ApiFCount; - Stage1ELostcount = airBattleData.ApiStage1.ApiELostcount; - Stage1ECount = airBattleData.ApiStage1.ApiECount; + AircraftLostStage1Friend = airBattleData.ApiStage1.ApiFLostcount; + AircraftTotalStage1Friend = airBattleData.ApiStage1.ApiFCount; + AircraftLostStage1Enemy = airBattleData.ApiStage1.ApiELostcount; + AircraftTotalStage1Enemy = airBattleData.ApiStage1.ApiECount; Stage1Display = GetStage1Display ( AirState, - Stage1FLostcount, - Stage1FCount, - Stage1ELostcount, - Stage1ECount + AircraftLostStage1Friend, + AircraftTotalStage1Friend, + AircraftLostStage1Enemy, + AircraftTotalStage1Enemy ); } @@ -177,18 +197,18 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) if (Stage2 is { } stage2) { - Stage2FLostcount = stage2.ApiFLostcount; - Stage2FCount = stage2.ApiFCount; - Stage2ELostcount = stage2.ApiELostcount; - Stage2ECount = stage2.ApiECount; + AircraftLostStage2Friend = stage2.ApiFLostcount; + AircraftTotalStage2Friend = stage2.ApiFCount; + AircraftLostStage2Enemy = stage2.ApiELostcount; + AircraftTotalStage2Enemy = stage2.ApiECount; ApiAirFire = stage2.ApiAirFire; } else if (Stage2Jet is { } stage2Jet) { - Stage2FLostcount = stage2Jet.ApiFLostcount; - Stage2FCount = stage2Jet.ApiFCount; - Stage2ELostcount = stage2Jet.ApiELostcount; - Stage2ECount = stage2Jet.ApiECount; + AircraftLostStage2Friend = stage2Jet.ApiFLostcount; + AircraftTotalStage2Friend = stage2Jet.ApiFCount; + AircraftLostStage2Enemy = stage2Jet.ApiELostcount; + AircraftTotalStage2Enemy = stage2Jet.ApiECount; } StringBuilder sb = new(); @@ -203,8 +223,8 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) } sb.AppendLine(); - sb.AppendLine($" {BattleRes.Friendly}: -{Stage2FLostcount}/{Stage2FCount}"); - sb.Append($" {BattleRes.Enemy}: -{Stage2ELostcount}/{Stage2ECount}"); + sb.AppendLine($" {BattleRes.Friendly}: -{AircraftLostStage2Friend}/{AircraftTotalStage2Friend}"); + sb.Append($" {BattleRes.Enemy}: -{AircraftLostStage2Enemy}/{AircraftTotalStage2Enemy}"); Stage2Display = sb.ToString(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttackUnit.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttackUnit.cs index 909f5e59c..5a6352036 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttackUnit.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttackUnit.cs @@ -36,8 +36,8 @@ public PhaseBaseAirAttackUnit(IKCDatabase kcDatabase, ApiAirBaseAttack airBattle Display = sb.ToString(); } - public PhaseBaseAirAttackUnit(ApiAirBaseInjection airBattleData, int waveIndex) - : base(airBattleData, waveIndex) + public PhaseBaseAirAttackUnit(IKCDatabase kcDatabase, ApiAirBaseInjection airBattleData, int waveIndex) + : base(kcDatabase, airBattleData, waveIndex) { Squadrons = airBattleData.ApiAirBaseData.Select(b => new BattleBaseAirCorpsSquadron { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs index a161dafa6..39e40590b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs @@ -1,17 +1,19 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using ElectronicObserver.Data; using ElectronicObserver.KancolleApi.Types.ApiReqMap.Models; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Models; using ElectronicObserver.KancolleApi.Types.Models; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Wpf; using ElectronicObserverTypes; using ElectronicObserverTypes.AntiAir; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseBaseAirRaid : PhaseBase +public class PhaseBaseAirRaid : PhaseBase, IPhaseAirBattle { public override string Title => BattleRes.BattlePhaseAirBaseRaid; @@ -21,23 +23,45 @@ public class PhaseBaseAirRaid : PhaseBase public AirState AirState { get; } - public int Stage1FLostcount { get; } - public int Stage1FCount { get; } - public int Stage1ELostcount { get; } - public int Stage1ECount { get; } + public int AircraftLostStage1Friend { get; } + public int AircraftTotalStage1Friend { get; } + public int AircraftLostStage1Enemy { get; } + public int AircraftTotalStage1Enemy { get; } - public int Stage2FLostcount { get; private set; } - public int Stage2FCount { get; private set; } - public int Stage2ELostcount { get; private set; } - public int Stage2ECount { get; private set; } + public int AircraftLostStage2Friend { get; private set; } + public int AircraftTotalStage2Friend { get; private set; } + public int AircraftLostStage2Enemy { get; private set; } + public int AircraftTotalStage2Enemy { get; private set; } + + [MemberNotNullWhen(true, nameof(ApiAirFire))] + public bool IsAACutinAvailable => ApiAirFire is not null; + + public int AACutInIndex => ApiAirFire?.ApiIdx ?? -1; + public string? AACutInShipName => IsAACutinAvailable switch + { + true => FleetsAfterPhase?.GetShip(new(ApiAirFire.ApiIdx, FleetFlag.Player))?.NameWithLevel, + _ => null, + }; + public int AACutInKind => ApiAirFire?.ApiKind ?? -1; /// /// AACI /// public ApiAirFire? ApiAirFire { get; private set; } + [MemberNotNullWhen(true, nameof(Stage1))] + public bool IsStage1Available => Stage1 is not null; + private ApiStage1? Stage1 => AirBattleData.ApiStage1; + + [MemberNotNullWhen(true, nameof(Stage2))] + public bool IsStage2Available => Stage2 is not null; + private ApiStage2? Stage2 => AirBattleData.ApiStage2; + + [MemberNotNullWhen(true, nameof(Stage3))] + public bool IsStage3Available => Stage3 is not null; + private ApiStage3? Stage3 => AirBattleData.ApiStage3; private int WaveIndex { get; } @@ -97,18 +121,18 @@ public PhaseBaseAirRaid(ApiDestructionBattle battle, int waveIndex = 0) if (AirBattleData.ApiStage1 is not null) { AirState = AirBattleData.ApiStage1.ApiDispSeiku; - Stage1FLostcount = AirBattleData.ApiStage1.ApiFLostcount; - Stage1FCount = AirBattleData.ApiStage1.ApiFCount; - Stage1ELostcount = AirBattleData.ApiStage1.ApiELostcount; - Stage1ECount = AirBattleData.ApiStage1.ApiECount; + AircraftLostStage1Friend = AirBattleData.ApiStage1.ApiFLostcount; + AircraftTotalStage1Friend = AirBattleData.ApiStage1.ApiFCount; + AircraftLostStage1Enemy = AirBattleData.ApiStage1.ApiELostcount; + AircraftTotalStage1Enemy = AirBattleData.ApiStage1.ApiECount; Stage1Display = GetStage1Display ( AirState, - Stage1FLostcount, - Stage1FCount, - Stage1ELostcount, - Stage1ECount + AircraftLostStage1Friend, + AircraftTotalStage1Friend, + AircraftLostStage1Enemy, + AircraftTotalStage1Enemy ); } @@ -142,10 +166,10 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) if (Stage2 is { } stage2) { - Stage2FLostcount = stage2.ApiFLostcount; - Stage2FCount = stage2.ApiFCount; - Stage2ELostcount = stage2.ApiELostcount; - Stage2ECount = stage2.ApiECount; + AircraftLostStage2Friend = stage2.ApiFLostcount; + AircraftTotalStage2Friend = stage2.ApiFCount; + AircraftLostStage2Enemy = stage2.ApiELostcount; + AircraftTotalStage2Enemy = stage2.ApiECount; ApiAirFire = stage2.ApiAirFire; StringBuilder sb = new(); @@ -160,8 +184,8 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) } sb.AppendLine(); - sb.AppendLine($" {BattleRes.Friendly}: -{Stage2FLostcount}/{Stage2FCount}"); - sb.Append($" {BattleRes.Enemy}: -{Stage2ELostcount}/{Stage2ECount}"); + sb.AppendLine($" {BattleRes.Friendly}: -{AircraftLostStage2Friend}/{AircraftTotalStage2Friend}"); + sb.Append($" {BattleRes.Enemy}: -{AircraftLostStage2Enemy}/{AircraftTotalStage2Enemy}"); Stage2Display = sb.ToString(); } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFactory.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFactory.cs index 51007c3ac..5f237236e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFactory.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFactory.cs @@ -33,14 +33,14 @@ public sealed class PhaseFactory(IKCDatabase kcDatabase) public PhaseJetBaseAirAttack? JetBaseAirAttack(ApiAirBaseInjection? a) => a switch { null => null, - _ => new(a), + _ => new(KcDatabase, a), }; [return: NotNullIfNotNull(nameof(a))] public PhaseJetAirBattle? JetAirBattle(ApiInjectionKouku? a) => a switch { null => null, - _ => new(a), + _ => new(KcDatabase, a), }; [return: NotNullIfNotNull(nameof(a))] diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index 5b6146944..633800077 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Text.Json; @@ -21,15 +22,44 @@ public class PhaseInitial : PhaseBase private IKCDatabase KcDatabase { get; } + /// + /// 自軍艦隊ID + /// + public int FriendFleetID { get; private set; } + public bool IsEnemyCombinedFleet { get; } - private bool IsBossDamaged { get; } + public bool IsBossDamaged { get; } public List? ApiCombatRation { get; } public List? ApiCombatRationCombined { get; } - private List FriendInitialHPs { get; } - private List FriendMaxHPs { get; } + public List FriendInitialHPs { get; } + public List FriendMaxHPs { get; } + public List? FriendInitialHPsEscort { get; } + public List? FriendMaxHPsEscort { get; } + + public List EnemyMembersInstance { get; } + public List? EnemyMembersEscortInstance { get; } + + public int[] EnemyMembers => EnemyMembersInstance.Select(s => s?.MasterShip.ShipID ?? -1).ToArray(); + public int[] EnemyLevels => EnemyMembersInstance.Select(s => s?.Level ?? -1).ToArray(); + public List EnemyInitialHPs => EnemyMembersInstance.Select(s => s?.HPCurrent ?? -1).ToList(); + public int[] EnemyMaxHPs => EnemyMembersInstance.Select(s => s?.HPMax ?? -1).ToArray(); + public List> EnemyParameters { get; } + public int[][] EnemySlots => EnemyMembersInstance.Select(s => s?.SlotInstance.Select(e => e.EquipmentID).ToArray() ?? []).ToArray(); + + [MemberNotNullWhen(true, nameof(EnemyMembersEscort))] + [MemberNotNullWhen(true, nameof(EnemyLevelsEscort))] + [MemberNotNullWhen(true, nameof(EnemyMaxHPsEscort))] + [MemberNotNullWhen(true, nameof(EnemyParametersEscort))] + [MemberNotNullWhen(true, nameof(EnemySlotsEscort))] + public bool IsEnemyCombined => EnemyMembersEscortInstance is not null; + + public int[]? EnemyMembersEscort => EnemyMembersEscortInstance?.Select(s => s?.MasterShip.ShipID ?? -1).ToArray(); + public int[]? EnemyLevelsEscort => EnemyMembersEscortInstance?.Select(s => s?.Level ?? -1).ToArray(); + public List? EnemyInitialHPsEscort => EnemyMembersEscortInstance?.Select(s => s?.HPCurrent ?? -1).ToList(); + public int[]? EnemyMaxHPsEscort => EnemyMembersEscortInstance?.Select(s => s?.HPMax ?? -1).ToArray(); + public List>? EnemyParametersEscort { get; } + public int[][]? EnemySlotsEscort => EnemyMembersEscortInstance?.Select(s => s?.SlotInstance.Select(e => e.EquipmentID).ToArray() ?? []).ToArray(); - private List EnemyMembersInstance { get; } - private List? EnemyMembersEscortInstance { get; } private string PlayerMainFleetTitle => FleetsAfterPhase?.EscortFleet switch { @@ -169,6 +199,7 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo { KcDatabase = kcDatabase; FleetsBeforePhase = fleets; + FriendFleetID = battle.ApiDeckId; if (battle is IAirBaseBattle { ApiAirBaseAttack: not null } abb) { @@ -207,6 +238,8 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo Escape(fleets.Fleet, battle.ApiEscapeIdx); + EnemyParameters = battle.ApiEParam; + EnemyMembersInstance = battle.ApiShipKe .Zip(battle.ApiShipLv, (id, level) => (Id: id, Level: level)) .Zip(battle.ApiESlot, (t, equipment) => (t.Id, t.Level, Equipment: equipment)) @@ -249,6 +282,9 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IPlayerCombinedFleetBattle battle) : this(kcDatabase, fleets, (IBattleApiResponse)battle) { + FriendInitialHPsEscort = battle.ApiFNowhpsCombined; + FriendMaxHPsEscort = battle.ApiFMaxhpsCombined; + ApiCombatRationCombined = battle.ApiCombatRationCombined; SetEscortFleetHp(fleets, battle); Escape(fleets.EscortFleet, battle.ApiEscapeIdxCombined); @@ -265,6 +301,9 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IEnemyCombinedF public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ICombinedBattleApiResponse battle) : this(kcDatabase, fleets, (IBattleApiResponse)battle) { + FriendInitialHPsEscort = battle.ApiFNowhpsCombined; + FriendMaxHPsEscort = battle.ApiFMaxhpsCombined; + ApiCombatRationCombined = battle.ApiCombatRationCombined; SetEscortFleetHp(fleets, battle); Escape(fleets.EscortFleet, battle.ApiEscapeIdxCombined); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetAirBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetAirBattle.cs index 35de85d7c..082e84389 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetAirBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetAirBattle.cs @@ -1,13 +1,10 @@ using ElectronicObserver.KancolleApi.Types.Models; +using ElectronicObserverTypes.Data; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseJetAirBattle : PhaseAirBattleBase +public class PhaseJetAirBattle(IKCDatabase kcDatabase, ApiInjectionKouku apiInjectionKouku) + : PhaseAirBattleBase(kcDatabase, apiInjectionKouku) { public override string Title => BattleRes.BattlePhaseJet; - - public PhaseJetAirBattle(ApiInjectionKouku apiInjectionKouku) : base(apiInjectionKouku) - { - - } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs index 04155b446..8d4238996 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using ElectronicObserver.KancolleApi.Types.Models; +using ElectronicObserverTypes.Data; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; @@ -9,9 +10,9 @@ public class PhaseJetBaseAirAttack : PhaseBase public List Units { get; } = new(); - public PhaseJetBaseAirAttack(ApiAirBaseInjection apiAirBaseInjection) + public PhaseJetBaseAirAttack(IKCDatabase kcDatabase, ApiAirBaseInjection apiAirBaseInjection) { - Units.Add(new(apiAirBaseInjection, 0)); + Units.Add(new(kcDatabase, apiAirBaseInjection, 0)); } public override BattleFleets EmulateBattle(BattleFleets battleFleets) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs index 928bf493b..7ff8e6852 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs @@ -3,6 +3,7 @@ using System.Linq; using ElectronicObserver.Data; using ElectronicObserverTypes; +using ElectronicObserverTypes.Attacks; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; @@ -16,6 +17,7 @@ public sealed class PhaseNightBattleAttackViewModel : AttackViewModelBase public IShipData Defender { get; } public List DefenderHpBeforeAttacks { get; } = new(); + public NightAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } @@ -28,6 +30,7 @@ public PhaseNightBattleAttackViewModel(BattleFleets fleets, PhaseNightBattleAtta Attacker = fleets.GetShip(AttackerIndex)!; DefenderIndex = defenderIndex; Defender = fleets.GetShip(DefenderIndex)!; + AttackType = attack.AttackType; Attacks = attack.Defenders .Where(d => d.Defender == DefenderIndex) .Select(d => new NightAttack diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs index 186402285..0ca529ec4 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs @@ -23,13 +23,13 @@ public class PhaseNightInitial : PhaseBase public int FlareIndexFriend { get; } public int FlareIndexEnemy { get; } - private IShipData? FlareFriend { get; } - private IShipData? FlareEnemy { get; } + public IShipData? FlareFriend { get; } + public IShipData? FlareEnemy { get; } public int SearchlightIndexFriend { get; } public int SearchlightIndexEnemy { get; } private IShipData? SearchlightFriend { get; } - private IShipData? SearchlightEnemy { get; } + public IShipData? SearchlightEnemy { get; } public IEquipmentData? SearchlightEquipmentFriend => GetSearchlight(SearchlightFriend); public IEquipmentData? SearchlightEquipmentEnemy => GetSearchlight(SearchlightEnemy); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSearching.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSearching.cs index 7a2c8f828..1975869f8 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSearching.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSearching.cs @@ -4,18 +4,18 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseSearching : PhaseBase +public class PhaseSearching(IFirstBattleApiResponse battle) : PhaseBase { public override string Title => BattleRes.PhaseSearching; - public FormationType PlayerFormationType { get; } - public FormationType EnemyFormationType { get; } - public EngagementType EngagementType { get; } + public FormationType PlayerFormationType { get; } = (FormationType)battle.ApiFormation[0]; + public FormationType EnemyFormationType { get; } = (FormationType)battle.ApiFormation[1]; + public EngagementType EngagementType { get; } = (EngagementType)battle.ApiFormation[2]; public DetectionType PlayerDetectionType { get; } public DetectionType EnemyDetectionType { get; } - public int? SmokeCount { get; } + public int? SmokeCount { get; } = battle.ApiSmokeType; public string Display => $""" {BattleRes.Formation}: {Constants.GetFormation(PlayerFormationType)} / {BattleRes.EnemyFormation}: {Constants.GetFormation(EnemyFormationType)} @@ -29,15 +29,6 @@ public class PhaseSearching : PhaseBase _ => "", }; - public PhaseSearching(IFirstBattleApiResponse battle) - { - PlayerFormationType = (FormationType)battle.ApiFormation[0]; - EnemyFormationType = (FormationType)battle.ApiFormation[1]; - EngagementType = (EngagementType)battle.ApiFormation[2]; - - SmokeCount = battle.ApiSmokeType; - } - public PhaseSearching(IDaySearch battle) : this((IFirstBattleApiResponse)battle) { PlayerDetectionType = battle.ApiSearch[0]; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs index f4225b235..7f19123dc 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using ElectronicObserver.Data; using ElectronicObserver.Utility.Data; using ElectronicObserverTypes; using ElectronicObserverTypes.Attacks; @@ -18,7 +17,7 @@ public sealed class PhaseShellingAttackViewModel : AttackViewModelBase public IShipData Defender { get; } public List DefenderHpBeforeAttacks { get; } = new(); - private DayAttackKind AttackType { get; } + public DayAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs index 605ef1bb3..201d7f289 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs @@ -22,7 +22,7 @@ public class PhaseSupport : PhaseBase public int? Stage2FLostcount { get; } public int? Stage2FCount { get; } - private SupportType ApiSupportFlag { get; } + public SupportType SupportFlag { get; } private bool IsNightSupport { get; } private List Damages { get; } @@ -35,9 +35,9 @@ public class PhaseSupport : PhaseBase private List Attacks { get; } = new(); public List AttackDisplays { get; } = new(); - public PhaseSupport(SupportType apiSupportFlag, ApiSupportInfo apiSupportInfo, bool isNightSupport) + public PhaseSupport(SupportType supportFlag, ApiSupportInfo apiSupportInfo, bool isNightSupport) { - ApiSupportFlag = apiSupportFlag; + SupportFlag = supportFlag; IsNightSupport = isNightSupport; static object? SupportAttack(SupportType apiSupportFlag, ApiSupportInfo apiSupportInfo) => apiSupportFlag switch @@ -47,7 +47,7 @@ public PhaseSupport(SupportType apiSupportFlag, ApiSupportInfo apiSupportInfo, b _ => null, }; - Damages = SupportAttack(apiSupportFlag, apiSupportInfo) switch + Damages = SupportAttack(supportFlag, apiSupportInfo) switch { ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 => attack.ApiStage3.ApiEdam, @@ -57,7 +57,7 @@ ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 _ => new(), }; - Criticals = SupportAttack(apiSupportFlag, apiSupportInfo) switch + Criticals = SupportAttack(supportFlag, apiSupportInfo) switch { ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 => attack.ApiStage3.ApiEclFlag.Select(h => h switch @@ -71,7 +71,7 @@ ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 _ => new(), }; - SupportFleetId = SupportAttack(apiSupportFlag, apiSupportInfo) switch + SupportFleetId = SupportAttack(supportFlag, apiSupportInfo) switch { ApiSupportAiratack attack => attack.ApiDeckId, ApiSupportHourai attack => attack.ApiDeckId, @@ -107,7 +107,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { Attacks.Add(new() { - AttackType = ApiSupportFlag, + AttackType = SupportFlag, Defenders = new() { new() @@ -130,7 +130,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { Attacks.Add(new() { - AttackType = ApiSupportFlag, + AttackType = SupportFlag, Defenders = new() { new() diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/RadarBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/RadarBattleData.cs index a1de64ac0..089265ce6 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/RadarBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/RadarBattleData.cs @@ -1,12 +1,13 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; -public abstract class RadarBattleData : FirstBattleData +public abstract class RadarBattleData : FirstBattleData, IBaseAirAttack { protected PhaseJetBaseAirAttack? JetBaseAirAttack { get; } - protected PhaseBaseAirAttack? BaseAirAttack { get; } + public PhaseBaseAirAttack? BaseAirAttack { get; } protected PhaseRadar? Shelling1 { get; } protected RadarBattleData(PhaseFactory phaseFactory, BattleFleets fleets, IRadarBattleApiResponse battle) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs index 942b3be72..514ea8865 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs @@ -49,7 +49,7 @@ public void AddResult(ISortieBattleResultApi result) _ => new(result), }; - ResultRank = string.Format(ConstantsRes.BattleDetail_ResultRank, BattleResult.WinRank); + ResultRank = string.Format(ConstantsRes.BattleDetail_ResultRank, BattleResult.Rank); ResultMvpMain = BattleResult.MvpIndex switch { @@ -107,10 +107,10 @@ public void AddResult(ISortieBattleResultApi result) bool damageTaken = hpBeforeBattle > hpAfterBattle; - return (BattleResult?.WinRank, damageTaken) switch + return (WinRank: BattleResult?.Rank, damageTaken) switch { ("S", false) => "SS", - _ => BattleResult?.WinRank, + _ => BattleResult?.Rank, }; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs index d3c9dcae1..2c156ea20 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs @@ -9,7 +9,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; public class BattleResult { - public string WinRank { get; } + public string Rank { get; } public int AdmiralExp { get; } public int MvpIndex { get; } public int? MvpIndexCombined { get; } @@ -37,7 +37,7 @@ public class BattleResult public BattleResult(ISortieBattleResultApi result) { - WinRank = result.ApiWinRank; + Rank = result.ApiWinRank; AdmiralExp = result.ApiGetExp; MvpIndex = result.ApiMvp - 1; BaseExp = result.ApiGetBaseExp; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/AirBaseCostCalculator.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/AirBaseCostCalculator.cs index deb6a67ff..219af4c97 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/AirBaseCostCalculator.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/AirBaseCostCalculator.cs @@ -140,7 +140,7 @@ private static int GetAircraftLossFromRaid(SortieDetailViewModel sortieDetails) .FirstOrDefault() ?.Units .DistinctBy(u => u.AirBaseId) - .Select(u => u.Stage1FCount); + .Select(u => u.AircraftTotalStage1Friend); if (aircraftInBattle is null) return 0; @@ -168,11 +168,11 @@ private static int GetAircraftLossFromAirBattles(IEnumerable nodes) .SelectMany(n => n.AllPhases) .Sum(p => p switch { - PhaseBaseAirRaid r => r.Stage1FLostcount + r.Stage2FLostcount, + PhaseBaseAirRaid r => r.AircraftLostStage1Friend + r.AircraftLostStage2Friend, PhaseBaseAirAttack r => r.Units .Select((u, i) => (i % 2) switch { - 1 => u.Stage1FLostcount + u.Stage2FLostcount, + 1 => u.AircraftLostStage1Friend + u.AircraftLostStage2Friend, _ => 0, }) .Sum(), diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/SupplyCostCalculator.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/SupplyCostCalculator.cs index e37447978..951a8b56c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/SupplyCostCalculator.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieCostViewer/SupplyCostCalculator.cs @@ -237,7 +237,7 @@ private static SortieCostModel CalculateSupplyCost(SortieDetailViewModel details { bauxite += battleNode.FirstBattle.Phases .OfType() - .Sum(b => b.Stage1FLostcount + b.Stage2FLostcount) * 5; + .Sum(b => b.AircraftLostStage1Friend + b.AircraftLostStage2Friend) * 5; if (battleNode.BattleResult is null) continue; diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index aa5ff8c1f..00e2de9df 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -9,17 +9,20 @@ using CommunityToolkit.Mvvm.Input; using ElectronicObserver.Data; using ElectronicObserver.Data.Battle; -using ElectronicObserver.Data.Battle.Detail; -using ElectronicObserver.Data.Battle.Phase; using ElectronicObserver.Observer; using ElectronicObserver.Resource; using ElectronicObserver.Utility; using ElectronicObserver.ViewModels; using ElectronicObserver.ViewModels.Translations; using ElectronicObserver.Window.Dialog.BattleDetail; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; using ElectronicObserver.Window.Wpf.Battle.ViewModels; using ElectronicObserverTypes; using ElectronicObserverTypes.AntiAir; +using BattleIndex = ElectronicObserver.Data.Battle.BattleIndex; using Color = System.Drawing.Color; namespace ElectronicObserver.Window.Wpf.Battle; @@ -226,7 +229,7 @@ private void ShowBattleDetail() BattleDetailView dialog = new(new BattleDetailViewModel { - BattleDetailText = BattleDetailDescriptor.GetBattleDetail(bm), + BattleDetailText = "", // todo BattleDetailDescriptor.GetBattleDetail(bm), }); dialog.Show(App.Current!.MainWindow!); @@ -298,8 +301,17 @@ private void Updated(string apiname, dynamic data) SetFormation(bm); SetSearchingResult(bm.BattleDay); - SetBaseAirAttack(bm.BattleDay.BaseAirAttack); - SetAerialWarfare(bm.BattleDay.JetAirBattle, bm.BattleDay.AirBattle); + + if (bm.BattleDay is IBaseAirAttack baa) + { + SetBaseAirAttack(baa.BaseAirAttack); + } + + if (bm.BattleDay is IAirBattle ab) + { + SetAerialWarfare(ab.JetAirBattle, ab.AirBattle); + } + SetHPBar(bm.BattleDay); SetDamageRate(bm); @@ -312,8 +324,9 @@ private void Updated(string apiname, dynamic data) case "api_req_battle_midnight/battle": case "api_req_practice/midnight_battle": { + if (bm.BattleNight is not INightInitial b) return; - SetNightBattleEvent(bm.BattleNight.NightInitial); + SetNightBattleEvent(b.NightInitial); SetHPBar(bm.BattleNight); SetDamageRate(bm); @@ -325,12 +338,13 @@ private void Updated(string apiname, dynamic data) case "api_req_battle_midnight/sp_midnight": { + if (bm.BattleNight is not INightInitial b) return; SetFormation(bm); ClearBaseAirAttack(); ClearAerialWarfare(); ClearSearchingResult(); - SetNightBattleEvent(bm.BattleNight.NightInitial); + SetNightBattleEvent(b.NightInitial); SetHPBar(bm.BattleNight); SetDamageRate(bm); @@ -342,12 +356,13 @@ private void Updated(string apiname, dynamic data) case "api_req_sortie/airbattle": { + if (bm.BattleDay is not BattleAirBattle bab) return; SetFormation(bm); - SetSearchingResult(bm.BattleDay); - SetBaseAirAttack(bm.BattleDay.BaseAirAttack); - SetAerialWarfare(bm.BattleDay.JetAirBattle, bm.BattleDay.AirBattle, ((BattleAirBattle)bm.BattleDay).AirBattle2); - SetHPBar(bm.BattleDay); + SetSearchingResult(bab); + SetBaseAirAttack(bab.BaseAirAttack); + SetAerialWarfare(bab.JetAirBattle, bab.AirBattle, bab.AirBattle2); + SetHPBar(bab); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -358,8 +373,7 @@ private void Updated(string apiname, dynamic data) case "api_req_sortie/night_to_day": { - // 暫定 - var battle = bm.BattleNight as BattleDayFromNight; + if (bm.BattleNight is not BattleNormalDayFromNight battle) return; SetFormation(bm); ClearAerialWarfare(); @@ -394,8 +408,17 @@ private void Updated(string apiname, dynamic data) SetFormation(bm); SetSearchingResult(bm.BattleDay); - SetBaseAirAttack(bm.BattleDay.BaseAirAttack); - SetAerialWarfare(bm.BattleDay.JetAirBattle, bm.BattleDay.AirBattle); + + if (bm.BattleDay is IBaseAirAttack baa) + { + SetBaseAirAttack(baa.BaseAirAttack); + } + + if (bm.BattleDay is IAirBattle ab) + { + SetAerialWarfare(ab.JetAirBattle, ab.AirBattle); + } + SetHPBar(bm.BattleDay); SetDamageRate(bm); @@ -407,12 +430,13 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/airbattle": { + if (bm.BattleDay is not BattleCombinedAirBattle bcab) return; SetFormation(bm); - SetSearchingResult(bm.BattleDay); - SetBaseAirAttack(bm.BattleDay.BaseAirAttack); - SetAerialWarfare(bm.BattleDay.JetAirBattle, bm.BattleDay.AirBattle, ((BattleCombinedAirBattle)bm.BattleDay).AirBattle2); - SetHPBar(bm.BattleDay); + SetSearchingResult(bcab); + SetBaseAirAttack(bcab.BaseAirAttack); + SetAerialWarfare(bcab.JetAirBattle, bcab.AirBattle, bcab.AirBattle2); + SetHPBar(bcab); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -424,8 +448,9 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/midnight_battle": case "api_req_combined_battle/ec_midnight_battle": { + if (bm.BattleNight is not INightInitial b) break; - SetNightBattleEvent(bm.BattleNight.NightInitial); + SetNightBattleEvent(b.NightInitial); SetHPBar(bm.BattleNight); SetDamageRate(bm); @@ -437,12 +462,13 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/sp_midnight": { + if (bm.BattleNight is not INightInitial b) break; SetFormation(bm); ClearAerialWarfare(); ClearSearchingResult(); ClearBaseAirAttack(); - SetNightBattleEvent(bm.BattleNight.NightInitial); + SetNightBattleEvent(b.NightInitial); SetHPBar(bm.BattleNight); SetDamageRate(bm); @@ -454,13 +480,13 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/ec_night_to_day": { - var battle = bm.BattleNight as BattleDayFromNight; + var battle = bm.BattleNight as DayFromNightBattleData; SetFormation(bm); ClearAerialWarfare(); ClearSearchingResult(); ClearBaseAirAttack(); - SetNightBattleEvent(battle.NightInitial); + SetNightBattleEvent(battle!.NightInitial); if (battle.NextToDay) { @@ -512,9 +538,11 @@ private void Updated(string apiname, dynamic data) ///
private void SetFormation(BattleManager bm) { - FormationFriendText = Constants.GetFormationShort(bm.FirstBattle.Searching.FormationFriend); - FormationEnemyText = Constants.GetFormationShort(bm.FirstBattle.Searching.FormationEnemy); - FormationText = Constants.GetEngagementForm(bm.FirstBattle.Searching.EngagementForm); + if (bm.FirstBattle is not FirstBattleData { Searching: { } searching }) return; + + FormationFriendText = Constants.GetFormationShort(searching.PlayerFormationType); + FormationEnemyText = Constants.GetFormationShort(searching.EnemyFormationType); + FormationText = Constants.GetEngagementForm(searching.EngagementType); @@ -563,10 +591,10 @@ private void SetFormation(BattleManager bm) FleetEnemyBackColor = FleetEnemyEscortBackColor = Color.Transparent.ToBrush(); } - FormationForeColor = (bm.FirstBattle.Searching.EngagementForm switch + FormationForeColor = (searching.EngagementType switch { - 3 => Configuration.Config.UI.Color_Green, - 4 => Configuration.Config.UI.Color_Red, + EngagementType.TAdvantage => Configuration.Config.UI.Color_Green, + EngagementType.TDisadvantage => Configuration.Config.UI.Color_Red, _ => Configuration.Config.UI.ForeColor, }).ToBrush(); } @@ -576,27 +604,29 @@ private void SetFormation(BattleManager bm) ///
private void SetSearchingResult(BattleData bd) { - int search = bd.Searching.SearchingFriend; + if (bd is not FirstBattleData { Searching: { } searching }) return; + + DetectionType search = searching.PlayerDetectionType; SearchingFriendText = Constants.GetSearchingResultShort(search); SearchingFriendIcon = search switch { <= 0 => null, - < 4 => EquipmentIconType.Seaplane, + < DetectionType.Failure => EquipmentIconType.Seaplane, _ => EquipmentIconType.Radar, }; SearchingFriendToolTip = null; - Smoker1Active = bd.Searching.SmokeCount >= 1; - Smoker2Active = bd.Searching.SmokeCount >= 2; - Smoker3Active = bd.Searching.SmokeCount >= 3; + Smoker1Active = searching.SmokeCount >= 1; + Smoker2Active = searching.SmokeCount >= 2; + Smoker3Active = searching.SmokeCount >= 3; - search = bd.Searching.SearchingEnemy; + search = searching.EnemyDetectionType; SearchingEnemyText = Constants.GetSearchingResultShort(search); SearchingEnemyIcon = search switch { <= 0 => null, - < 4 => EquipmentIconType.Seaplane, + < DetectionType.Failure => EquipmentIconType.Seaplane, _ => EquipmentIconType.Radar, }; SearchingEnemyToolTip = null; @@ -623,9 +653,9 @@ private void ClearSearchingResult() /// /// 基地航空隊フェーズの結果を設定します。 /// - private void SetBaseAirAttack(PhaseBaseAirAttack pd) + private void SetBaseAirAttack(PhaseBaseAirAttack? pd) { - if (pd?.IsAvailable != true) + if (pd is null) { ClearBaseAirAttack(); return; @@ -637,10 +667,10 @@ private void SetBaseAirAttack(PhaseBaseAirAttack pd) StringBuilder sb = new(); int index = 1; - foreach (PhaseBaseAirAttack.PhaseBaseAirAttackUnit phase in pd.AirAttackUnits) + foreach (PhaseBaseAirAttackUnit phase in pd.Units) { sb.AppendFormat(GeneralRes.BaseWave + " - " + GeneralRes.BaseAirCorps + " :\r\n", - index, phase.AirUnitID); + index, phase.AirBaseId); if (phase.IsStage1Available) { @@ -649,7 +679,7 @@ private void SetBaseAirAttack(PhaseBaseAirAttack pd) " -{2}/{3} | {4}\r\n", phase.AircraftLostStage1Friend, phase.AircraftTotalStage1Friend, phase.AircraftLostStage1Enemy, phase.AircraftTotalStage1Enemy, - Constants.GetAirSuperiority(phase.AirSuperiority)); + Constants.GetAirSuperiority(phase.AirState)); } if (phase.IsStage2Available) @@ -679,19 +709,13 @@ private void ClearBaseAirAttack() /// /// 航空戦表示用ヘルパー /// - private sealed class AerialWarfareFormatter + private sealed class AerialWarfareFormatter(IPhaseAirBattle? air, string phaseName) { - public PhaseAirBattleBase? Air { get; } - public string PhaseName { get; set; } - - public AerialWarfareFormatter(PhaseAirBattleBase? air, string phaseName) - { - Air = air; - PhaseName = phaseName; - } + public IPhaseAirBattle? Air { get; } = air; + public string PhaseName { get; set; } = phaseName; [MemberNotNullWhen(true, nameof(Air))] - public bool Enabled => Air is { IsAvailable: true }; + public bool Enabled => Air is not null; [MemberNotNullWhen(true, nameof(Air))] public bool Stage1Enabled => Enabled && Air.IsStage1Available; @@ -732,7 +756,7 @@ private static ArgumentOutOfRangeException InvalidStage(int phase) => _ => throw InvalidStage(stage), }; - public int GetTouchAircraft(bool isFriend) => isFriend switch + public string? GetTouchAircraft(bool isFriend) => isFriend switch { true when Enabled => Air.TouchAircraftFriend, _ when Enabled => Air.TouchAircraftEnemy, @@ -740,7 +764,7 @@ private static ArgumentOutOfRangeException InvalidStage(int phase) => }; } - private void SetAerialWarfare(PhaseAirBattleBase? phaseJet, PhaseAirBattleBase phase1) + private void SetAerialWarfare(IPhaseAirBattle? phaseJet, IPhaseAirBattle? phase1) => SetAerialWarfare(phaseJet, phase1, null); /// @@ -749,7 +773,7 @@ private void SetAerialWarfare(PhaseAirBattleBase? phaseJet, PhaseAirBattleBase p /// 噴式航空戦のデータ。発生していなければ null /// 第一次航空戦(通常航空戦)のデータ。 /// 第二次航空戦のデータ。発生していなければ null - private void SetAerialWarfare(PhaseAirBattleBase? phaseJet, PhaseAirBattleBase phase1, PhaseAirBattleBase? phase2) + private void SetAerialWarfare(IPhaseAirBattle? phaseJet, IPhaseAirBattle? phase1, IPhaseAirBattle? phase2) { List phases = new() { @@ -811,13 +835,11 @@ void ClearAACutinLabel() .Where(p => p.Stage1Enabled) .ToList(); - AirSuperiorityText = Constants.GetAirSuperiority(((AirState?)phases[1].Air?.AirSuperiority) ?? AirState.Unknown); - AirSuperiorityForeColor = (phases[1].Air?.AirSuperiority switch + AirSuperiorityText = Constants.GetAirSuperiority((phases[1].Air?.AirState) ?? AirState.Unknown); + AirSuperiorityForeColor = (phases[1].Air?.AirState switch { - // AS+ or AS - 1 or 2 => Configuration.Config.UI.Color_Green, - // AI or AI- - 3 or 4 => Configuration.Config.UI.Color_Red, + AirState.Supremacy or AirState.Superiority => Configuration.Config.UI.Color_Green, + AirState.Denial or AirState.Incapability => Configuration.Config.UI.Color_Red, _ => Configuration.Config.UI.ForeColor, }).ToBrush(); @@ -825,7 +847,7 @@ void ClearAACutinLabel() AirSuperiorityToolTip = needAppendInfo switch { true => string.Join("", phases1.Select(p => - $"{p.PhaseName}{Constants.GetAirSuperiority(((AirState?)p.Air?.AirSuperiority) ?? AirState.Unknown)}\r\n")), + $"{p.PhaseName}{Constants.GetAirSuperiority(p.Air?.AirState ?? AirState.Unknown)}\r\n")), _ => null, }; @@ -840,10 +862,10 @@ void ClearAACutinLabel() string? toolTip = currentToolTip; EquipmentIconType? icon; - if (phases1.Any(p => p.GetTouchAircraft(isFriend) > 0)) + if (phases1.Any(p => p.GetTouchAircraft(isFriend) is not null)) { icon = EquipmentIconType.Seaplane; - toolTip += FormBattle.Contact + "\r\n" + string.Join("\r\n", phases1.Select(p => $"{p.PhaseName}{(KCDatabase.Instance.MasterEquipments[p.GetTouchAircraft(isFriend)]?.NameEN ?? FormBattle.None)}")); + toolTip += FormBattle.Contact + "\r\n" + string.Join("\r\n", phases1.Select(p => $"{p.PhaseName}{(p.GetTouchAircraft(isFriend) ?? FormBattle.None)}")); } else { @@ -858,7 +880,7 @@ void ClearAACutinLabel() } else { - AirSuperiorityText = Constants.GetAirSuperiority(-1); + AirSuperiorityText = Constants.GetAirSuperiority(AirState.Unknown); AirSuperiorityToolTip = null; AirStage1FriendText = "-"; @@ -969,7 +991,6 @@ private void ClearAerialWarfare() /// private void SetHPBar(BattleData bd) { - KCDatabase db = KCDatabase.Instance; bool isPractice = bd.IsPractice; bool isFriendCombined = bd.IsFriendCombined; bool isEnemyCombined = bd.IsEnemyCombined; @@ -980,8 +1001,8 @@ private void SetHPBar(BattleData bd) IsEnemyCombinedFleet = isEnemyCombined; var initial = bd.Initial; - var resultHPs = bd.ResultHPs; - var attackDamages = bd.AttackDamages; + var resultHPs = bd.ResultHPs.ToList(); + // var attackDamages = bd.AttackDamages; /* foreach (var bar in HPBars) @@ -1013,7 +1034,7 @@ void SetEnemyBackground(int index) } // friend main - for (int i = 0; i < initial.FriendInitialHPs.Length; i++) + for (int i = 0; i < initial.FriendInitialHPs.Count; i++) { int refindex = BattleIndex.Get(BattleSides.FriendMain, i); @@ -1038,9 +1059,9 @@ void SetEnemyBackground(int index) } else { - IShipData ship = bd.Initial.FriendFleet.MembersInstance[i]; + IShipData ship = bd.FleetsBeforeBattle.Fleet.MembersInstance[i]; name = ship.NameWithLevel; - isEscaped = bd.Initial.FriendFleet.EscapedShipList.Contains(ship.MasterID); + isEscaped = bd.FleetsBeforeBattle.Fleet.EscapedShipList.Contains(ship.MasterID); isLandBase = ship.MasterShip.IsLandBase; bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.MasterShip.ShipType); } @@ -1052,9 +1073,9 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, isLandBase, isEscaped), - attackDamages[refindex], - bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, isLandBase, isEscaped) + // todo attackDamages[refindex] + // todo bd.GetBattleDetail(refindex) ); bar.BackColor = isEscaped switch @@ -1072,29 +1093,29 @@ void SetEnemyBackground(int index) // enemy main - for (int i = 0; i < initial.EnemyInitialHPs.Length; i++) + for (int i = 0; i < initial.EnemyInitialHPs.Count; i++) { int refindex = BattleIndex.Get(BattleSides.EnemyMain, i); if (initial.EnemyInitialHPs[i] != -1) { - EnableHPBar(refindex, initial.EnemyInitialHPs[i], resultHPs[refindex], initial.EnemyMaxHPs[i], initial.IsEnemyTargetable[i]); - IShipDataMaster ship = bd.Initial.EnemyMembersInstance[i]; + IShipData ship = bd.Initial.EnemyMembersInstance[i]; + EnableHPBar(refindex, ship.HPCurrent, resultHPs[refindex], ship.HPMax, ship.CanBeTargeted); var bar = HPBars[refindex]; - bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.ShipType); + bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.MasterShip.ShipType); SetEnemyBackground(refindex); bar.ToolTip = string.Format("{0} Lv. {1}\r\nHP: ({2} → {3})/{4} ({5}) [{6}]\r\n\r\n{7}", - ship.NameWithClass, - initial.EnemyLevels[i], + ship.MasterShip.NameWithClass, + ship.Level, Math.Max(bar.PrevValue, 0), Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.IsLandBase), - bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase) + // todo bd.GetBattleDetail(refindex) ); } else @@ -1107,7 +1128,7 @@ void SetEnemyBackground(int index) // friend escort if (isFriendCombined) { - for (int i = 0; i < initial.FriendInitialHPsEscort!.Length; i++) + for (int i = 0; i < initial.FriendInitialHPsEscort!.Count; i++) { int refindex = BattleIndex.Get(BattleSides.FriendEscort, i); @@ -1115,8 +1136,8 @@ void SetEnemyBackground(int index) { EnableHPBar(refindex, initial.FriendInitialHPsEscort[i], resultHPs[refindex], initial.FriendMaxHPsEscort![i], true); - IShipData? ship = bd.Initial.FriendFleetEscort.MembersInstance![i]; - bool isEscaped = bd.Initial.FriendFleetEscort.EscapedShipList.Contains(ship.MasterID); + IShipData ship = bd.FleetsBeforeBattle.EscortFleet!.MembersInstance[i]!; + bool isEscaped = bd.FleetsBeforeBattle.EscortFleet.EscapedShipList.Contains(ship.MasterID); var bar = HPBars[refindex]; bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.MasterShip.ShipType); @@ -1129,9 +1150,9 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase, isEscaped), - attackDamages[refindex], - bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase, isEscaped) + // todo attackDamages[refindex] + // todo bd.GetBattleDetail(refindex) ); bar.BackColor = isEscaped switch @@ -1172,24 +1193,23 @@ void SetEnemyBackground(int index) if (initial.EnemyInitialHPsEscort![i] != -1) { - EnableHPBar(refindex, initial.EnemyInitialHPsEscort[i], resultHPs[refindex], initial.EnemyMaxHPsEscort![i], initial.IsEnemyTargetableEscort[i]); - - IShipDataMaster ship = bd.Initial.EnemyMembersEscortInstance![i]; + IShipData ship = bd.Initial.EnemyMembersEscortInstance![i]!; + EnableHPBar(refindex, initial.EnemyInitialHPsEscort[i], resultHPs[refindex], ship.HPMax, ship.CanBeTargeted); var bar = HPBars[refindex]; - bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.ShipType); + bar.Text = KCDatabase.Instance.Translation.Ship.TypeNameShort(ship.MasterShip.ShipType); SetEnemyBackground(refindex); bar.ToolTip = string.Format("{0} Lv. {1}\r\nHP: ({2} → {3})/{4} ({5}) [{6}]\r\n\r\n{7}", - ship.NameWithClass, - bd.Initial.EnemyLevelsEscort![i], + ship.MasterShip.NameWithClass, + ship.Level, Math.Max(bar.PrevValue, 0), Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.IsLandBase), - bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase) + // todo bd.GetBattleDetail(refindex) ); } else @@ -1211,25 +1231,28 @@ void SetEnemyBackground(int index) { // support PhaseSupport? support = null; - if (bd is BattleDayFromNight bddn && (bddn.NightSupport?.IsAvailable ?? false)) + if (bd is BattleNormalDayFromNight { NightSupport: { } nightSupport }) { - support = bddn.NightSupport; + support = nightSupport; } - support ??= bd.Support; + if (bd is DayBattleData { Support: { } s }) + { + support ??= s; + } - if (support?.IsAvailable ?? false) + if (support is not null) { FleetFriendIcon = support.SupportFlag switch { - 1 => EquipmentIconType.CarrierBasedTorpedo, - 2 => EquipmentIconType.MainGunLarge, - 3 => EquipmentIconType.Torpedo, - 4 => EquipmentIconType.DepthCharge, + SupportType.Aerial => EquipmentIconType.CarrierBasedTorpedo, + SupportType.Shelling => EquipmentIconType.MainGunLarge, + SupportType.Torpedo => EquipmentIconType.Torpedo, + SupportType.AntiSubmarine => EquipmentIconType.DepthCharge, _ => EquipmentIconType.Unknown, }; - FleetFriendToolTip = FormBattle.SupportExpedition + "\r\n" + support.GetBattleDetail(); + FleetFriendToolTip = FormBattle.SupportExpedition + "\r\n"; // todo + support.GetBattleDetail(); FleetFriendText = ((isFriendCombined || hasFriend7thShip) && isEnemyCombined) switch { @@ -1257,6 +1280,7 @@ void SetEnemyBackground(int index) if (!isBaseAirRaid) { + /* todo foreach (int i in bd.MVPShipIndexes) { HPBars[BattleIndex.Get(BattleSides.FriendMain, i)].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; @@ -1269,6 +1293,7 @@ void SetEnemyBackground(int index) HPBars[BattleIndex.Get(BattleSides.FriendEscort, i)].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; } } + */ } } @@ -1332,7 +1357,7 @@ private void SetDamageRate(BattleManager bm) ///
private void SetNightBattleEvent(PhaseNightInitial pd) { - FleetData fleet = pd.FriendFleet; + IFleetData fleet = pd.FleetsBeforePhase!.Fleet; //味方探照灯判定 { @@ -1340,9 +1365,9 @@ private void SetNightBattleEvent(PhaseNightInitial pd) if (index != -1) { - IShipData ship = fleet.MembersInstance[index]; + IShipData ship = fleet.MembersInstance[index]!; - AirStage1FriendText = "#" + (index + (pd.IsFriendEscort ? 6 : 0) + 1); + AirStage1FriendText = "#" + (index + 1); AirStage1FriendForeColor = Configuration.Config.UI.ForeColor.ToBrush(); AirStage1FriendIcon = EquipmentIconType.Searchlight; AirStage1FriendToolTip = GeneralRes.SearchlightUsed + ": " + ship.NameWithLevel; @@ -1358,10 +1383,10 @@ private void SetNightBattleEvent(PhaseNightInitial pd) int index = pd.SearchlightIndexEnemy; if (index != -1) { - AirStage1EnemyText = "#" + (index + (pd.IsEnemyEscort ? 6 : 0) + 1); + AirStage1EnemyText = "#" + (index + 1); AirStage1EnemyForeColor = Configuration.Config.UI.ForeColor.ToBrush(); AirStage1EnemyIcon = EquipmentIconType.Searchlight; - AirStage1EnemyToolTip = GeneralRes.SearchlightUsed + ": " + pd.SearchlightEnemyInstance.NameWithClass; + AirStage1EnemyToolTip = GeneralRes.SearchlightUsed + ": " + pd.SearchlightEnemy!.MasterShip.NameWithClass; } else { @@ -1370,22 +1395,22 @@ private void SetNightBattleEvent(PhaseNightInitial pd) } //夜間触接判定 - if (pd.TouchAircraftFriend != -1) + if (pd.TouchAircraftFriend is not null) { SearchingFriendText = GeneralRes.NightContact; SearchingFriendIcon = EquipmentIconType.Seaplane; - SearchingFriendToolTip = GeneralRes.NightContacting + ": " + KCDatabase.Instance.MasterEquipments[pd.TouchAircraftFriend].NameEN; + SearchingFriendToolTip = GeneralRes.NightContacting + ": " + pd.TouchAircraftFriend.NameEN; } else { SearchingFriendToolTip = null; } - if (pd.TouchAircraftEnemy != -1) + if (pd.TouchAircraftEnemy is not null) { SearchingEnemyText = GeneralRes.NightContact; SearchingEnemyIcon = EquipmentIconType.Seaplane; - SearchingEnemyToolTip = GeneralRes.NightContacting + ": " + KCDatabase.Instance.MasterEquipments[pd.TouchAircraftEnemy].NameEN; + SearchingEnemyToolTip = GeneralRes.NightContacting + ": " + pd.TouchAircraftEnemy.NameEN; } else { @@ -1394,14 +1419,12 @@ private void SetNightBattleEvent(PhaseNightInitial pd) //照明弾投射判定 { - int index = pd.FlareIndexFriend; - - if (index != -1) + if (pd.FlareFriend is not null) { - AirStage2FriendText = "#" + (index + 1); + AirStage2FriendText = "#" + (pd.FlareIndexFriend + 1); AirStage2FriendForeColor = Configuration.Config.UI.ForeColor.ToBrush(); AirStage2FriendIcon = EquipmentIconType.StarShell; - AirStage2FriendToolTip = GeneralRes.StarShellUsed + ": " + pd.FlareFriendInstance.NameWithLevel; + AirStage2FriendToolTip = GeneralRes.StarShellUsed + ": " + pd.FlareFriend.NameWithLevel; } else @@ -1411,14 +1434,12 @@ private void SetNightBattleEvent(PhaseNightInitial pd) } { - int index = pd.FlareIndexEnemy; - - if (index != -1) + if (pd.FlareEnemy is not null) { - AirStage2EnemyText = "#" + (index + 1); + AirStage2EnemyText = "#" + (pd.FlareIndexEnemy + 1); AirStage2EnemyForeColor = Configuration.Config.UI.ForeColor.ToBrush(); AirStage2EnemyIcon = EquipmentIconType.StarShell; - AirStage2EnemyToolTip = GeneralRes.StarShellUsed + ": " + pd.FlareEnemyInstance.NameWithClass; + AirStage2EnemyToolTip = GeneralRes.StarShellUsed + ": " + pd.FlareEnemy.MasterShip.NameWithClass; } else { @@ -1436,19 +1457,14 @@ private void SetMVPShip(BattleManager bm) { bool isCombined = bm.IsCombinedBattle; - BattleData bd = bm.StartsFromDayBattle switch - { - true => bm.BattleDay, - _ => bm.BattleNight, - }; - - BattleResultData br = bm.Result; + BattleData bd = bm.BattleNight ?? bm.BattleDay; + BattleResult br = bm.Result; - FleetData friend = bd.Initial.FriendFleet; - FleetData? escort = isCombined switch + IFleetData friend = bd.FleetsBeforeBattle.Fleet; + IFleetData? escort = isCombined switch { false => null, - _ => bd.Initial.FriendFleetEscort, + _ => bd.FleetsBeforeBattle.EscortFleet, }; for (int i = 0; i < friend.Members.Count; i++) @@ -1457,7 +1473,7 @@ private void SetMVPShip(BattleManager bm) { HPBars[i].BackColor = Configuration.Config.UI.Battle_ColorHPBarsEscaped; } - else if (br.MVPIndex == i + 1) + else if (br.MvpIndex == i + 1) { HPBars[i].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; } @@ -1475,7 +1491,7 @@ private void SetMVPShip(BattleManager bm) { HPBars[i + 6].BackColor = Configuration.Config.UI.Battle_ColorHPBarsEscaped; } - else if (br.MVPIndexCombined == i + 1) + else if (br.MvpIndexCombined == i + 1) { HPBars[i + 6].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; } diff --git a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs index 7eea6da3b..451a9b361 100644 --- a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs @@ -13,6 +13,7 @@ using ElectronicObserver.Utility.Data; using ElectronicObserver.ViewModels; using ElectronicObserver.ViewModels.Translations; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; using ElectronicObserver.Window.Wpf.Compass.ViewModels; using ElectronicObserverTypes; using ElectronicObserverTypes.Attacks; @@ -384,7 +385,7 @@ System.Drawing.Color GetColorFromEventKind(int kind) } else if (Db.Battle.HeavyBaseAirRaids.Any()) { - int apiLostKind = (int)Db.Battle.HeavyBaseAirRaids.Last().RawData.api_lost_kind; + int apiLostKind = Db.Battle.HeavyBaseAirRaids.Last().BaseAirRaid?.ApiLostKind ?? 0; TextEventKindIcon = EquipmentIconType.CarrierBasedBomber; TextEventKindToolTip = FormCompass.AirRaid + Constants.GetAirRaidDamage(apiLostKind); @@ -450,7 +451,7 @@ private void NextEnemyFleetCandidate(int offset) .Select(f => new EnemyFleetElementViewModel { EnemyFleetCandidate = f.First(), - Formations = f.Select(fleet => fleet.Formation).ToList() + Formations = f.Select(fleet => (FormationType)fleet.Formation).ToList(), }) .ToList(); @@ -561,13 +562,14 @@ private void UpdateEnemyFleetInstant(bool isPractice = false) CurrentViewModel = BattleViewModel; BattleManager bm = KCDatabase.Instance.Battle; - BattleData bd = bm.FirstBattle; - int[] enemies = bd.Initial.EnemyMembers; - int[][] slots = bd.Initial.EnemySlots; - int[] levels = bd.Initial.EnemyLevels; - int[][] parameters = bd.Initial.EnemyParameters; - int[] hps = bd.Initial.EnemyMaxHPs; + if (bm.FirstBattle is not FirstBattleData bd) return; + + int[] enemies = bd.Initial.EnemyMembers.ToArray(); + int[][] slots = bd.Initial.EnemySlots.ToArray(); + int[] levels = bd.Initial.EnemyLevels.ToArray(); + List> parameters = bd.Initial.EnemyParameters; + int[] hps = bd.Initial.EnemyMaxHPs.ToArray(); _enemyFleetCandidate = null; @@ -583,7 +585,7 @@ private void UpdateEnemyFleetInstant(bool isPractice = false) TextEventDetailToolTip = GeneralRes.EnemyFleetID + ": " + efcurrent.FleetID.ToString("x16"); } - TextFormationText = Constants.GetFormationShort(bd.Searching.FormationEnemy); + TextFormationText = Constants.GetFormationShort(bd.Searching.EnemyFormationType); { int air = Calculator.GetAirSuperiority(enemies, slots); diff --git a/ElectronicObserver/Window/Wpf/Compass/ViewModels/EnemyFleetElementViewModel.cs b/ElectronicObserver/Window/Wpf/Compass/ViewModels/EnemyFleetElementViewModel.cs index c45bbe057..1894f8287 100644 --- a/ElectronicObserver/Window/Wpf/Compass/ViewModels/EnemyFleetElementViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Compass/ViewModels/EnemyFleetElementViewModel.cs @@ -30,7 +30,7 @@ public class EnemyFleetElementViewModel : ObservableObject public bool HasEscortFleet => EscortFleetMember.Any(ship => ship.ShipId > 0); - public List Formations { get; init; } = new(); + public List Formations { get; init; } = new(); public string FormationString => string.Join('/', Formations.Select(Constants.GetFormationShort)); diff --git a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs index 066191ddd..03fa748ab 100644 --- a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs +++ b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs @@ -154,7 +154,7 @@ private void Updated(string apiname, dynamic data) break; case "api_req_practice/battle": - _inSortie = new List() { KCDatabase.Instance.Battle.BattleDay.Initial.FriendFleetID }; + _inSortie = [ KCDatabase.Instance.Battle.BattleDay.Initial.FriendFleetID ]; break; } From 9f0163baaa651539977941e6ef5b67bf5a8c7eb7 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 11 Jul 2024 13:01:06 +0900 Subject: [PATCH 02/38] WIP --- .../Data/Battle/BattleManager.cs | 136 +++++++++++++++--- .../Sortie/Battle/BattleData.cs | 19 ++- .../Sortie/Battle/BattleIndex.cs | 6 + .../Sortie/Battle/Phase/PhaseAirBattleBase.cs | 2 +- .../Sortie/Battle/Phase/PhaseBase.cs | 2 +- .../Sortie/Battle/Phase/PhaseBaseAirAttack.cs | 4 +- .../Sortie/Battle/Phase/PhaseBaseAirRaid.cs | 2 +- .../Battle/Phase/PhaseClosingTorpedo.cs | 3 +- .../Battle/Phase/PhaseFriendlyShelling.cs | 2 +- .../Battle/Phase/PhaseFriendlySupportInfo.cs | 2 +- .../Sortie/Battle/Phase/PhaseInitial.cs | 39 +++-- .../Battle/Phase/PhaseJetBaseAirAttack.cs | 4 +- .../Sortie/Battle/Phase/PhaseNightBattle.cs | 4 +- .../Battle/Phase/PhaseOpeningTorpedo.cs | 3 +- .../Sortie/Battle/Phase/PhaseShelling.cs | 4 +- .../Sortie/Battle/Phase/PhaseSupport.cs | 2 +- .../Sortie/Battle/Phase/PhaseTorpedoAttack.cs | 4 +- .../Sortie/Battle/SecondNightBattleData.cs | 5 +- .../Window/Wpf/Battle/BattleViewModel.cs | 27 ++-- 19 files changed, 207 insertions(+), 63 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index f8f523f0b..2188ada2a 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -1,8 +1,35 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text.Json; +using CommunityToolkit.Mvvm.DependencyInjection; using ElectronicObserver.Database.KancolleApi; +using ElectronicObserver.KancolleApi.Types; +using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.Battle; +using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.SpMidnight; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battleresult; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.BattleWater; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EachBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EachBattleWater; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcMidnightBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdAirbattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdShooting; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.MidnightBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.SpMidnight; +using ElectronicObserver.KancolleApi.Types.ApiReqMap.Models; +using ElectronicObserver.KancolleApi.Types.ApiReqMap.Next; +using ElectronicObserver.KancolleApi.Types.ApiReqMap.Start; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.Battle; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.BattleResult; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Airbattle; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battle; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battleresult; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdAirbattle; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdShooting; using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.Resource.Record; using ElectronicObserver.Utility.Mathematics; @@ -12,6 +39,7 @@ using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; using ElectronicObserverTypes; +using ElectronicObserverTypes.Data; using ElectronicObserverTypes.Extensions; using ElectronicObserverTypes.Mocks; @@ -203,17 +231,40 @@ public override void LoadFromRequest(string apiname, Dictionary } + private BattleFactory BattleFactory => Ioc.Default.GetRequiredService(); + + private BattleFleets Fleets + { + get + { + IFleetData fleet = KCDatabase.Instance.Fleet.Fleets.Values + .First(f => f.IsInSortie); + + return new(fleet) + { + FleetId = fleet.FleetID, + CombinedFlag = KCDatabase.Instance.Fleet.CombinedFlag, + NodeSupportFleetId = KCDatabase.Instance.Fleet.NodeSupportFleet ?? 0, + BossSupportFleetId = KCDatabase.Instance.Fleet.BossSupportFleet ?? 0, + }; + } + } + public override void LoadFromResponse(string apiname, dynamic data) { + IKCDatabase db = KCDatabase.Instance; + //base.LoadFromResponse( apiname, data ); //不要 + object? apiData = DeserializeResponse(apiname, data.ToString()); + HeavyBaseAirRaids.Clear(); switch (apiname) { - /* case "api_req_map/start": case "api_req_map/next": + { BattleDay = null; BattleNight = null; Result = null; @@ -221,16 +272,17 @@ public override void LoadFromResponse(string apiname, dynamic data) Compass = new CompassData(); Compass.LoadFromResponse(apiname, data); - if (Compass.HasAirRaid) + if (apiData is ApiReqMapNextResponse { ApiDestructionBattle: { } battle }) { BattleMode = BattleModes.BaseAirRaid; - BattleDay = new BattleBaseAirRaid(); - BattleDay.LoadFromResponse(apiname, Compass.AirRaidData); + BattleDay = BattleFactory.CreateBattle(battle, Fleets); BattleFinished(); } - break; - + } + break; + /* case "api_req_map/air_raid": + { BattleMode = BattleModes.BaseAirRaid; // BattleDay = new BattleHeavyBaseAirRaid(); // BattleDay.LoadFromResponse(apiname, data.api_destruction_battle[0]); @@ -241,20 +293,27 @@ public override void LoadFromResponse(string apiname, dynamic data) HeavyBaseAirRaids.Add(raid); } BattleFinished(); - break; - + } + break; + */ case "api_req_sortie/battle": + { + if (apiData is not ApiReqSortieBattleResponse battle) break; + BattleMode = BattleModes.Normal; - BattleDay = new BattleNormalDay(); - BattleDay.LoadFromResponse(apiname, data); - break; + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_battle_midnight/battle": - BattleNight = new BattleNormalNight(); - BattleNight.TakeOverParameters(BattleDay); - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqBattleMidnightBattleResponse battle) break; + + BattleNight = BattleFactory.CreateBattle(battle, BattleDay.FleetsAfterBattle); + } + break; + /* case "api_req_battle_midnight/sp_midnight": BattleMode = BattleModes.NightOnly; BattleDay = null; @@ -375,15 +434,22 @@ public override void LoadFromResponse(string apiname, dynamic data) BattleNight.TakeOverParameters(BattleDay); BattleNight.LoadFromResponse(apiname, data); break; + */ case "api_req_sortie/battleresult": case "api_req_combined_battle/battleresult": case "api_req_practice/battle_result": - Result = new BattleResultData(); - Result.LoadFromResponse(apiname, data); + { + if (apiData is not ISortieBattleResultApi result) break; + + Result = result switch + { + ApiReqCombinedBattleBattleresultResponse r => new(r), + _ => new(result), + }; BattleFinished(); break; - */ + } case "api_port/port": Compass = null; @@ -404,6 +470,40 @@ public override void LoadFromResponse(string apiname, dynamic data) } } + private static object? DeserializeResponse(string apiName, string json) => apiName switch + { + "api_req_map/start" => JsonSerializer.Deserialize(json), + + "api_req_sortie/battle" => JsonSerializer.Deserialize(json), + "api_req_battle_midnight/sp_midnight" => JsonSerializer.Deserialize(json), + "api_req_sortie/airbattle" => JsonSerializer.Deserialize(json), + "api_req_sortie/ld_airbattle" => JsonSerializer.Deserialize(json), + "api_req_sortie/night_to_day" => throw new NotImplementedException(), + "api_req_sortie/ld_shooting" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/battle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/sp_midnight" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/airbattle" => throw new NotImplementedException(), + "api_req_combined_battle/battle_water" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/ld_airbattle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/ec_battle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/ec_night_to_day" => throw new NotImplementedException(), + "api_req_combined_battle/each_battle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/each_battle_water" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/ld_shooting" => JsonSerializer.Deserialize(json), + + "api_req_battle_midnight/battle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/midnight_battle" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/ec_midnight_battle" => JsonSerializer.Deserialize(json), + + "api_req_sortie/battleresult" => JsonSerializer.Deserialize(json), + "api_req_combined_battle/battleresult" => JsonSerializer.Deserialize(json), + + "api_req_practice/battle" => JsonSerializer.Deserialize(json), + "api_req_practice/battle_result" => JsonSerializer.Deserialize(json), + + _ => null, + }; + /// /// 戦闘終了時に各種データの収集を行います。 /// diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index 66e92cea8..339e2bba6 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -3,6 +3,7 @@ using System.Linq; using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; +using ElectronicObserverTypes; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; @@ -21,9 +22,18 @@ public abstract class BattleData public bool IsEnemyCombined => FleetsBeforeBattle.EnemyEscortFleet is not null; public bool IsBaseAirRaid => this is BattleBaseAirRaid; - public IEnumerable ResultHPs => FleetsAfterBattle - .SortieShips() - .Select(s => s?.HPCurrent ?? 0); + public IEnumerable ResultHPs => GetHpList(FleetsAfterBattle.Fleet) + .Concat(GetHpList(FleetsAfterBattle.EscortFleet)) + .Take(12) + .Concat(GetHpList(FleetsAfterBattle.EnemyFleet)) + .Concat(GetHpList(FleetsAfterBattle.EnemyEscortFleet)); + + private static IEnumerable GetHpList(IFleetData? fleet) => + fleet?.MembersInstance + .Select(s => s?.HPCurrent ?? 0) + .Concat(Enumerable.Repeat(0, 6)) + .Take(Math.Max(fleet.MembersInstance.Count, 6)) + ?? Enumerable.Repeat(0, 6); public IEnumerable AirBaseBeforeAfter => FleetsBeforeBattle.AirBases .Zip(FleetsAfterBattle.AirBases, (before, after) => (Before: before, After: after)) @@ -48,6 +58,7 @@ public abstract class BattleData public PhaseInitial Initial { get; } public IEnumerable Phases => AllPhases().OfType(); + public List AttackDamages { get; } = [.. Enumerable.Repeat(0, 24)]; protected BattleData(PhaseFactory phaseFactory, BattleFleets fleets, IBattleApiResponse battle) { @@ -62,7 +73,7 @@ protected void EmulateBattle() { foreach (PhaseBase phase in Phases) { - FleetsAfterBattle = phase.EmulateBattle(FleetsAfterBattle); + FleetsAfterBattle = phase.EmulateBattle(FleetsAfterBattle, AttackDamages); } } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs index e2f5f92d8..c1a45d76b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs @@ -5,4 +5,10 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; public record BattleIndex(int Index, FleetFlag FleetFlag) { public string Display => $"#{Index + 1}"; + + public int ToFlatIndex() => FleetFlag switch + { + FleetFlag.Player => Index, + _ => Index + 12, + }; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs index a01eea686..fdede952e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs @@ -190,7 +190,7 @@ protected PhaseAirBattleBase(IKCDatabase kcDatabase, IApiJetAirBattle airBattleD LaunchedShipIndexEnemy = GetLaunchedShipIndex(airBattleData.ApiPlaneFrom, 1); } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs index 80d483c25..475a95554 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs @@ -14,7 +14,7 @@ public abstract class PhaseBase public BattleFleets? FleetsBeforePhase { get; protected set; } public BattleFleets? FleetsAfterPhase { get; protected set; } - public virtual BattleFleets EmulateBattle(BattleFleets battleFleets) + public virtual BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttack.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttack.cs index 143a5392f..f9bb74a15 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttack.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirAttack.cs @@ -20,14 +20,14 @@ public PhaseBaseAirAttack(IKCDatabase kcDatabase, List apiAirB } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; foreach (PhaseBaseAirAttackUnit attackUnit in Units) { - FleetsAfterPhase = attackUnit.EmulateBattle(FleetsAfterPhase); + FleetsAfterPhase = attackUnit.EmulateBattle(FleetsAfterPhase, damages); } return FleetsAfterPhase.Clone(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs index 39e40590b..133ebd4e1 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs @@ -159,7 +159,7 @@ public PhaseBaseAirRaid(ApiDestructionBattle battle, int waveIndex = 0) Display = sb.ToString(); } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseClosingTorpedo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseClosingTorpedo.cs index fbe9d9378..90ca68842 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseClosingTorpedo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseClosingTorpedo.cs @@ -12,7 +12,7 @@ public sealed class PhaseClosingTorpedo(ApiRaigekiClass apiRaigekiClass) : Phase private List Attacks { get; } = []; - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; @@ -24,6 +24,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { AttackDisplays.Add(new(FleetsAfterPhase, attack)); AddDamage(FleetsAfterPhase, attack.Defenders.First().Defender, attack.Defenders.First().Damage); + damages[attack.Attacker.ToFlatIndex()] += attack.Defenders.Sum(d => d.Damage); } return FleetsAfterPhase.Clone(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs index 36d64eabc..f17c41770 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs @@ -89,7 +89,7 @@ public PhaseFriendlyShelling(IKCDatabase kcDatabase, ApiFriendlyBattle apiFriend } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs index 970328951..9ce637ba6 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs @@ -60,7 +60,7 @@ public PhaseFriendlySupportInfo(ApiFriendlyInfo apiFriendlyInfo) } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index 633800077..de83316ff 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -44,7 +44,7 @@ public class PhaseInitial : PhaseBase public List EnemyInitialHPs => EnemyMembersInstance.Select(s => s?.HPCurrent ?? -1).ToList(); public int[] EnemyMaxHPs => EnemyMembersInstance.Select(s => s?.HPMax ?? -1).ToArray(); public List> EnemyParameters { get; } - public int[][] EnemySlots => EnemyMembersInstance.Select(s => s?.SlotInstance.Select(e => e.EquipmentID).ToArray() ?? []).ToArray(); + public int[][] EnemySlots => EnemyMembersInstance.Select(s => s?.SlotInstance.Select(e => e?.EquipmentID ?? -1).ToArray() ?? []).ToArray(); [MemberNotNullWhen(true, nameof(EnemyMembersEscort))] [MemberNotNullWhen(true, nameof(EnemyLevelsEscort))] @@ -58,7 +58,7 @@ public class PhaseInitial : PhaseBase public List? EnemyInitialHPsEscort => EnemyMembersEscortInstance?.Select(s => s?.HPCurrent ?? -1).ToList(); public int[]? EnemyMaxHPsEscort => EnemyMembersEscortInstance?.Select(s => s?.HPMax ?? -1).ToArray(); public List>? EnemyParametersEscort { get; } - public int[][]? EnemySlotsEscort => EnemyMembersEscortInstance?.Select(s => s?.SlotInstance.Select(e => e.EquipmentID).ToArray() ?? []).ToArray(); + public int[][]? EnemySlotsEscort => EnemyMembersEscortInstance?.Select(s => s?.SlotInstance.Select(e => e?.EquipmentID ?? -1).ToArray() ?? []).ToArray(); private string PlayerMainFleetTitle => FleetsAfterPhase?.EscortFleet switch @@ -238,7 +238,10 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo Escape(fleets.Fleet, battle.ApiEscapeIdx); - EnemyParameters = battle.ApiEParam; + EnemyParameters = battle.ApiEParam + .Concat(Enumerable.Repeat(0, 6).Select(_ => new List { 0, 0, 0, 0 })) + .Take(6) + .ToList(); EnemyMembersInstance = battle.ApiShipKe .Zip(battle.ApiShipLv, (id, level) => (Id: id, Level: level)) @@ -273,7 +276,8 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo }, _ => null, }) - .Cast() + .Concat(Enumerable.Repeat((IShipData?)null, 6)) + .Take(6) .ToList(); SetEnemyRange(EnemyMembersInstance); @@ -296,6 +300,11 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IEnemyCombinedF IsEnemyCombinedFleet = true; EnemyMembersEscortInstance = MakeEnemyEscortFleet(battle); SetEnemyRange(EnemyMembersEscortInstance); + + EnemyParametersEscort = battle.ApiEParamCombined + .Concat(Enumerable.Repeat(0, 6).Select(_ => new List { 0, 0, 0, 0 })) + .Take(6) + .ToList(); } public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ICombinedBattleApiResponse battle) @@ -311,6 +320,11 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ICombinedBattle IsEnemyCombinedFleet = true; EnemyMembersEscortInstance = MakeEnemyEscortFleet(battle); SetEnemyRange(EnemyMembersEscortInstance); + + EnemyParametersEscort = battle.ApiEParamCombined + .Concat(Enumerable.Repeat(0, 6).Select(_ => new List { 0, 0, 0, 0 })) + .Take(6) + .ToList(); } public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ICombinedNightBattleApiResponse battle) @@ -331,6 +345,11 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ApiDestructionB FriendInitialHPs = battle.ApiFNowhps; FriendMaxHPs = battle.ApiFMaxhps; + EnemyParameters = battle.ApiEParam + .Concat(Enumerable.Repeat(0, 6).Select(_ => new List { 0, 0, 0, 0 })) + .Take(6) + .ToList(); + EnemyMembersInstance = battle.ApiShipKe .Zip(battle.ApiShipLv, (id, level) => (Id: id, Level: level)) .Zip(battle.ApiESlot, (t, equipment) => (t.Id, t.Level, Equipment: equipment)) @@ -358,7 +377,8 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ApiDestructionB }, _ => null, }) - .Cast() + .Concat(Enumerable.Repeat((IShipData?)null, 6)) + .Take(6) .ToList(); } @@ -422,10 +442,11 @@ private static void Escape(IFleetData? fleet, List? escapeIndexes) }, _ => null, }) - .Cast() + .Concat(Enumerable.Repeat((IShipData?)null, 6)) + .Take(6) .ToList(); - private void SetEnemyRange(List ships) + private static void SetEnemyRange(List ships) { foreach (IShipData? ship in ships) { @@ -434,12 +455,12 @@ private void SetEnemyRange(List ships) s.Range = Math.Max(s.MasterShip.Range, s.AllSlotInstance switch { [] => 0, - _ => s.AllSlotInstance.Max(s => s?.MasterEquipment.Range ?? 0), + _ => s.AllSlotInstance.Max(e => e?.MasterEquipment.Range ?? 0), }); } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { battleFleets = FleetsBeforePhase!.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs index 8d4238996..081bdf41c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseJetBaseAirAttack.cs @@ -15,14 +15,14 @@ public PhaseJetBaseAirAttack(IKCDatabase kcDatabase, ApiAirBaseInjection apiAirB Units.Add(new(kcDatabase, apiAirBaseInjection, 0)); } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; foreach (PhaseBaseAirAttackUnit attackUnit in Units) { - FleetsAfterPhase = attackUnit.EmulateBattle(FleetsAfterPhase); + FleetsAfterPhase = attackUnit.EmulateBattle(FleetsAfterPhase, damages); } return FleetsAfterPhase.Clone(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs index 44b75e8cb..57860ae4a 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs @@ -73,7 +73,7 @@ public PhaseNightBattle(IKCDatabase kcDatabase, List apiAtEflag, List } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; @@ -107,6 +107,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) AttackDisplays.Add(new PhaseNightBattleAttackViewModel(FleetsAfterPhase, comboAttack, comboAttack.Defenders.First().Defender)); AddDamage(FleetsAfterPhase, atk.Defenders[i].Defender, atk.Defenders[i].Damage); + damages[comboAttack.Attacker.ToFlatIndex()] += comboAttack.Defenders.Sum(d => d.Damage); } } else @@ -115,6 +116,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { AttackDisplays.Add(new PhaseNightBattleAttackViewModel(FleetsAfterPhase, atk, atk.Defenders.First().Defender)); AddDamage(FleetsAfterPhase, defs.Key, defs.Sum(d => d.Damage)); + damages[atk.Attacker.ToFlatIndex()] += defs.Sum(d => d.Damage); } } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseOpeningTorpedo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseOpeningTorpedo.cs index 5a9f133fa..68344676d 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseOpeningTorpedo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseOpeningTorpedo.cs @@ -25,7 +25,7 @@ public PhaseOpeningTorpedo(ApiRaigekiClass apiRaigekiClass) ApiRaigekiClass = apiRaigekiClass; } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; @@ -45,6 +45,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { AttackDisplays.Add(new(FleetsAfterPhase, attack)); AddDamage(FleetsAfterPhase, attack.Defenders.First().Defender, attack.Defenders.First().Damage); + damages[attack.Attacker.ToFlatIndex()] += attack.Defenders.Sum(d => d.Damage); } return FleetsAfterPhase.Clone(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs index 585f972e2..2eb8c584b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs @@ -81,7 +81,7 @@ public PhaseShelling(IKCDatabase kcDatabase, ApiHougeki1 shellingData, DayShelli } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; @@ -102,6 +102,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) AttackDisplays.Add(new PhaseShellingAttackViewModel(FleetsAfterPhase, comboAttack)); AddDamage(FleetsAfterPhase, atk.Defenders[i].Defender, atk.Defenders[i].Damage); + damages[comboAttack.Attacker.ToFlatIndex()] += comboAttack.Defenders.Sum(d => d.Damage); } } else @@ -110,6 +111,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets) { AttackDisplays.Add(new PhaseShellingAttackViewModel(FleetsAfterPhase, atk)); AddDamage(FleetsAfterPhase, defs.Key, defs.Sum(d => d.Damage)); + damages[atk.Attacker.ToFlatIndex()] += defs.Sum(d => d.Damage); } } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs index 201d7f289..f8ce46e74 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs @@ -89,7 +89,7 @@ ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 } } - public override BattleFleets EmulateBattle(BattleFleets battleFleets) + public override BattleFleets EmulateBattle(BattleFleets battleFleets, List damages) { FleetsBeforePhase = battleFleets.Clone(); FleetsAfterPhase = battleFleets; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttack.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttack.cs index 935119796..fcf5bbe8e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttack.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttack.cs @@ -5,7 +5,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public record PhaseTorpedoAttack { - public BattleIndex Attacker { get; init; } + public required BattleIndex Attacker { get; init; } public DayAttackKind AttackType { get; init; } - public List Defenders { get; init; } = new(); + public List Defenders { get; init; } = []; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/SecondNightBattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/SecondNightBattleData.cs index 7593b9624..1c7164af3 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/SecondNightBattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/SecondNightBattleData.cs @@ -1,11 +1,12 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Interfaces; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; -public abstract class SecondNightBattleData : BattleData +public abstract class SecondNightBattleData : BattleData, INightInitial { - protected PhaseNightInitial? NightInitial { get; } + public PhaseNightInitial? NightInitial { get; } protected PhaseFriendlySupportInfo? FriendlySupportInfo { get; } protected PhaseFriendlyShelling? FriendlyShelling { get; } protected PhaseNightBattle? NightBattle { get; } diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index 00e2de9df..ead5287ec 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -1002,12 +1002,7 @@ private void SetHPBar(BattleData bd) var initial = bd.Initial; var resultHPs = bd.ResultHPs.ToList(); - // var attackDamages = bd.AttackDamages; - - /* - foreach (var bar in HPBars) - bar.SuspendUpdate(); - */ + List attackDamages = bd.AttackDamages; void EnableHPBar(int index, int initialHP, int resultHP, int maxHP, bool isTargetable) { @@ -1073,9 +1068,10 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, isLandBase, isEscaped) - // todo attackDamages[refindex] - // todo bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, isLandBase, isEscaped), + attackDamages[refindex], + "" + // todo bd.GetBattleDetail(refindex) ); bar.BackColor = isEscaped switch @@ -1114,7 +1110,8 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase), + "" // todo bd.GetBattleDetail(refindex) ); } @@ -1150,8 +1147,9 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase, isEscaped) - // todo attackDamages[refindex] + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase, isEscaped), + attackDamages[refindex], + "" // todo bd.GetBattleDetail(refindex) ); @@ -1208,8 +1206,9 @@ void SetEnemyBackground(int index) Math.Max(bar.Value, 0), bar.MaximumValue, bar.Value - bar.PrevValue, - Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase) - // todo bd.GetBattleDetail(refindex) + Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase), + "" + // todo bd.GetBattleDetail(refindex) ); } else From 5386cf6eb52f50c09fcf6280c492c2a378aba10f Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Fri, 12 Jul 2024 14:14:09 +0900 Subject: [PATCH 03/38] add battle detail descriptor --- .../BattleDetail/BattleDetailDescriptor.cs | 797 ++++++++++++++++++ .../Sortie/Battle/BattleData.cs | 6 + .../Sortie/Battle/Phase/PhaseBase.cs | 5 + .../Sortie/Battle/Phase/PhaseBaseAirRaid.cs | 2 +- .../Battle/Phase/PhaseFriendlyShelling.cs | 18 +- .../Sortie/Battle/Phase/PhaseInitial.cs | 2 + .../Sortie/Battle/Phase/PhaseNightInitial.cs | 2 +- .../Sortie/Battle/Phase/PhaseSupport.cs | 2 +- .../Window/Wpf/Battle/BattleViewModel.cs | 16 +- .../Mocks/EquipmentDataMock.cs | 2 + 10 files changed, 830 insertions(+), 22 deletions(-) create mode 100644 ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs new file mode 100644 index 000000000..d23523b7b --- /dev/null +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -0,0 +1,797 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ElectronicObserver.Data; +using ElectronicObserver.Data.Battle; +using ElectronicObserver.Resource.Record; +using ElectronicObserver.Utility.Data; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; +using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; +using ElectronicObserver.Window.Wpf; +using ElectronicObserverTypes; +using ElectronicObserverTypes.AntiAir; + +namespace ElectronicObserver.Window.Dialog.BattleDetail; + +public static class BattleDetailDescriptor +{ + public static string GetBattleDetail(BattleManager bm) + { + StringBuilder sb = new(); + + if (bm.IsPractice) + { + sb.AppendLine(BattleRes.Exercise); + + } + else + { + sb.AppendFormat("{0} ({1}-{2})", bm.Compass.MapInfo.NameEN, bm.Compass.MapAreaID, bm.Compass.MapInfoID); + if (bm.Compass.MapInfo.EventDifficulty > 0) + sb.AppendFormat(" [{0}]", Constants.GetDifficulty(bm.Compass.MapInfo.EventDifficulty)); + sb.Append(ConstantsRes.BattleDetail_Node).Append(bm.Compass.CellId.ToString()); + if (bm.Compass.EventID == 5) + sb.Append(ConstantsRes.BattleDetail_Boss); + sb.AppendLine(); + + MapInfoData mapinfo = bm.Compass.MapInfo; + if (!mapinfo.IsCleared) + { + if (mapinfo.RequiredDefeatedCount != -1) + { + sb.AppendFormat(BattleRes.ClearProgress, mapinfo.CurrentDefeatedCount, mapinfo.RequiredDefeatedCount) + .AppendLine(); + } + else if (mapinfo.MapHPMax > 0) + { + int current = bm.Compass.MapHPCurrent > 0 ? bm.Compass.MapHPCurrent : mapinfo.MapHPCurrent; + int max = bm.Compass.MapHPMax > 0 ? bm.Compass.MapHPMax : mapinfo.MapHPMax; + sb.AppendFormat("{0}{1}: {2} / {3}", mapinfo.CurrentGaugeIndex > 0 ? "#" + mapinfo.CurrentGaugeIndex + " " : "", mapinfo.GaugeType == 3 ? "TP" : "HP", current, max) + .AppendLine(); + } + } + } + if (bm.Result != null) + { + sb.AppendLine(bm.Result.EnemyFleetName); + } + sb.AppendLine(); + + if (bm.HeavyBaseAirRaids.Count > 0) + { + foreach (BattleBaseAirRaid baseAirRaid in bm.HeavyBaseAirRaids) + { + sb.AppendFormat("◆ {0} ◆\r\n", baseAirRaid.Title) + .AppendLine(GetBattleDetail(baseAirRaid)); + } + } + else + { + sb.AppendFormat("◆ {0} ◆\r\n", bm.FirstBattle.Title).AppendLine(GetBattleDetail(bm.FirstBattle)); + if (bm.SecondBattle != null) + sb.AppendFormat("◆ {0} ◆\r\n", bm.SecondBattle.Title).AppendLine(GetBattleDetail(bm.SecondBattle)); + } + + + if (bm.Result != null) + { + sb.AppendLine(GetBattleResult(bm)); + } + + return sb.ToString(); + } + + + public static string GetBattleDetail(BattleData battle) + { + StringBuilder sbmaster = new(); + bool isBaseAirRaid = battle.IsBaseAirRaid; + + foreach (PhaseBase phase in battle.Phases) + { + StringBuilder sb = new(); + + switch (phase) + { + case PhaseBaseAirRaid p: + + sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); + sb.Append(" ").AppendLine(string.Join(", ", + p.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()) + .DefaultIfEmpty(BattleRes.Empty))); + + GetBattleDetailPhaseAirBattle(sb, p); + + break; + + case PhaseAirBattle p: + + GetBattleDetailPhaseAirBattle(sb, p); + + break; + + case PhaseBaseAirAttack p: + + foreach (PhaseBaseAirAttackUnit a in p.Units) + { + sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.WaveIndex + 1); + + sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); + sb.Append(" ").AppendLine(string.Join(", ", + a.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()))); + + GetBattleDetailPhaseAirBattle(sb, a); + sb.Append(a.GetBattleDetail()); + } + + break; + + case PhaseJetAirBattle p: + GetBattleDetailPhaseAirBattle(sb, p); + + break; + + case PhaseJetBaseAirAttack p: + + foreach (PhaseBaseAirAttackUnit a in p.Units) + { + sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.WaveIndex + 1); + + sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); + sb.Append(" ").AppendLine(string.Join(", ", + a.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()))); + + GetBattleDetailPhaseAirBattle(sb, a); + sb.Append(a.GetBattleDetail()); + } + + break; + + case PhaseInitial p: + + + if (p.FleetsBeforePhase.EscortFleet != null) + sb.Append(ConstantsRes.BattleDetail_FriendMainFleet); + else + sb.Append(ConstantsRes.BattleDetail_FriendFleet); + + + void AppendFleetInfo(IFleetData fleet) + { + sb.Append($" {BattleRes.AirSuperiority} "); + sb.Append(GetRangeString(Calculator.GetAirSuperiority(fleet, false), + Calculator.GetAirSuperiority(fleet, true))); + + static double Truncate2(double value) => Math.Floor(value * 100) / 100; + sb.AppendFormat(BattleRes.Los, + Truncate2(Calculator.GetSearchingAbility_New33(fleet, 1)), + Truncate2(Calculator.GetSearchingAbility_New33(fleet, 2)), + Truncate2(Calculator.GetSearchingAbility_New33(fleet, 3)), + Truncate2(Calculator.GetSearchingAbility_New33(fleet, 4))); + } + + if (isBaseAirRaid) + { + sb.AppendLine(); + OutputFriendBase(sb, p.FriendInitialHPs, p.FriendMaxHPs); + } + else + { + AppendFleetInfo(p.FleetsBeforePhase.Fleet); + sb.AppendLine(); + OutputFriendData(sb, p.FleetsBeforePhase.Fleet, p.FriendInitialHPs, p.FriendMaxHPs); + } + + if (p.FleetsBeforePhase.EscortFleet != null) + { + sb.AppendLine(); + sb.Append(ConstantsRes.BattleDetail_FriendEscortFleet); + AppendFleetInfo(p.FleetsBeforePhase.EscortFleet); + sb.AppendLine(); + + OutputFriendData(sb, p.FleetsBeforePhase.EscortFleet, p.FriendInitialHPsEscort, + p.FriendMaxHPsEscort); + } + + + sb.AppendLine(); + + + void AppendEnemyFleetInfo(int[] members) + { + int air = 0; + int airbase = 0; + bool indeterminate = false; + for (int i = 0; i < members.Length; i++) + { + ShipParameterRecord.ShipParameterElement? param = + RecordManager.Instance.ShipParameter[members[i]]; + if (param == null) continue; + + if (param.DefaultSlot == null || param.Aircraft == null) + { + indeterminate = true; + continue; + } + + for (int s = 0; s < Math.Min(param.DefaultSlot.Length, param.Aircraft.Length); s++) + { + air += Calculator.GetAirSuperiority(param.DefaultSlot[s], param.Aircraft[s]); + if (KCDatabase.Instance.MasterEquipments[param.DefaultSlot[s]]?.IsAircraft ?? false) + airbase += Calculator.GetAirSuperiority(param.DefaultSlot[s], param.Aircraft[s], 0, + 0, AirBaseActionKind.Mission); + } + } + + sb.AppendFormat(BattleRes.AirBaseAirPower, air, airbase); + if (indeterminate) + sb.Append(BattleRes.ToBeDetermined); + } + + if (p.EnemyMembersEscort != null) + sb.Append(ConstantsRes.BattleDetail_EnemyMainFleet); + else + sb.Append(ConstantsRes.BattleDetail_EnemyFleet); + + AppendEnemyFleetInfo(p.EnemyMembers); + + if (p.IsBossDamaged) + sb.Append(BattleRes.BossDebuffed); + sb.AppendLine(); + + OutputEnemyData(sb, p.EnemyMembersInstance, p.EnemyLevels, p.EnemyInitialHPs, p.EnemyMaxHPs, + p.EnemySlotsInstance, p.EnemyParameters); + + + if (p.EnemyMembersEscort != null) + { + sb.AppendLine(); + sb.AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); + + AppendEnemyFleetInfo(p.EnemyMembersEscort); + sb.AppendLine(); + + OutputEnemyData(sb, p.EnemyMembersEscortInstance, p.EnemyLevelsEscort, p.EnemyInitialHPsEscort, + p.EnemyMaxHPsEscort, p.EnemySlotsEscortInstance, p.EnemyParametersEscort); + } + + sb.AppendLine(); + + if (battle.Phases.Any(ph => ph is PhaseBaseAirAttack or PhaseBaseAirRaid)) + { + sb.AppendLine(ConstantsRes.BattleDetail_AirBase); + GetBattleDetailBaseAirCorps(sb, KCDatabase.Instance.Battle.Compass.MapAreaID); // :( + sb.AppendLine(); + } + + if (p.ApiCombatRation?.Count > 0) + { + sb.AppendLine($"〈{BattleRes.CombatRation}〉"); + foreach (int index in p.ApiCombatRation) + { + IShipData? ship = p.FleetsBeforePhase.GetShip(new(index, FleetFlag.Player)); + + if (ship != null) + { + sb.AppendFormat(" {0} #{1}\r\n", ship.NameWithLevel, index + 1); + } + } + + sb.AppendLine(); + } + + break; + + case PhaseNightInitial p: + + { + IEquipmentDataMaster? eq = p.TouchAircraftFriend; + if (eq != null) + { + sb.Append(ConstantsRes.BattleDetail_FriendlyNightContact).AppendLine(eq.NameEN); + } + + eq = p.TouchAircraftEnemy; + if (eq != null) + { + sb.Append(ConstantsRes.BattleDetail_EnemyNightContact).AppendLine(eq.NameEN); + } + } + + { + if (p.SearchlightFriend is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_FriendlySearchlight + "\r\n", + p.SearchlightFriend.Name, p.SearchlightIndexFriend + 1); + } + + if (p.SearchlightEnemy is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_EnemySearchlight + "\r\n", + p.SearchlightEnemy.MasterShip.NameWithClass, p.SearchlightIndexEnemy + 1); + } + } + + if (p.FlareFriend is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", + p.FlareFriend.NameWithLevel, p.FlareIndexFriend + 1); + } + + if (p.FlareEnemy is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", + p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexEnemy + 1); + } + + sb.AppendLine(); + break; + + + case PhaseSearching p: + sb.Append($"{BattleRes.Formation}: ").Append(Constants.GetFormation(p.PlayerFormationType)); + sb.Append($" / {BattleRes.EnemyFormation}: ") + .AppendLine(Constants.GetFormation(p.EnemyFormationType)); + sb.Append($"{BattleRes.Engagement}: ").AppendLine(Constants.GetEngagementForm(p.EngagementType)); + sb.Append($"{BattleRes.Contact}: ").Append(Constants.GetSearchingResult(p.PlayerDetectionType)); + sb.Append($" / {BattleRes.EnemyContact}: ") + .AppendLine(Constants.GetSearchingResult(p.EnemyDetectionType)); + + if (p.SmokeCount > 0) + { + sb.AppendLine($"{BattleRes.SmokeScreen} x{p.SmokeCount}"); + } + + sb.AppendLine(); + + break; + + case PhaseSupport p: + if (p.SupportFleet is not null) + { + sb.AppendLine($"〈{BattleRes.SupportFleet}〉"); + OutputSupportData(sb, p.SupportFleet); + sb.AppendLine(); + } + + break; + + case PhaseFriendlySupportInfo p: + OutputFriendlySupportData(sb, p); + sb.AppendLine(); + break; + + case PhaseFriendlyShelling p: + if (p.SearchlightFriend is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_FriendlySearchlight + "\r\n", + p.SearchlightFriend.MasterShip.NameWithClass, p.SearchlightIndexFriend + 1); + } + + if (p.SearchlightEnemy is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_EnemySearchlight + "\r\n", + p.SearchlightEnemy.MasterShip.NameWithClass, p.SearchlightIndexEnemy + 1); + } + + if (p.FlareFriend is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", + p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexFriend + 1); + } + + if (p.FlareEnemy is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", + p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexEnemy + 1); + } + + sb.AppendLine(); + break; + + case PhaseFriendlyAirBattle p: + + GetBattleDetailPhaseAirBattle(sb, p); + + break; + } + + + if (!(phase is PhaseBaseAirAttack || phase is PhaseJetBaseAirAttack)) // 通常出力と重複するため + sb.Append(phase.GetBattleDetail()); + + if (sb.Length > 0) + { + sbmaster.AppendFormat("== {0} ==\r\n", phase.Title).Append(sb); + } + } + + + { + sbmaster.AppendLine(ConstantsRes.BattleDetail_BattleEnd); + + IFleetData? friend = battle.FleetsAfterBattle.FriendFleet; + IFleetData? friendescort = battle.FleetsAfterBattle.EscortFleet; + List enemy = battle.Initial.EnemyMembersInstance; + List? enemyescort = battle.Initial.EnemyMembersEscortInstance; + List resultHps = battle.ResultHPs.ToList(); + + if (friendescort != null) + sbmaster.AppendLine(ConstantsRes.BattleDetail_FriendMainFleet); + else + sbmaster.AppendLine(ConstantsRes.BattleDetail_FriendFleet); + + if (isBaseAirRaid) + { + + for (int i = 0; i < 6; i++) + { + if (battle.Initial.FriendMaxHPs[i] <= 0) + continue; + + OutputResultData(sbmaster, i, string.Format(BattleRes.Base, i + 1), + battle.Initial.FriendInitialHPs[i], resultHps[i], battle.Initial.FriendMaxHPs[i]); + } + + } + else + { + for (int i = 0; i < friend.Members.Count(); i++) + { + var ship = friend.MembersInstance[i]; + if (ship == null) + continue; + + OutputResultData(sbmaster, i, ship.Name, + battle.Initial.FriendInitialHPs[i], resultHps[i], battle.Initial.FriendMaxHPs[i]); + } + } + + if (friendescort != null) + { + sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_FriendEscortFleet); + + for (int i = 0; i < friendescort.Members.Count(); i++) + { + var ship = friendescort.MembersInstance[i]; + if (ship == null) + continue; + + OutputResultData(sbmaster, i + 6, ship.Name, + battle.Initial.FriendInitialHPsEscort[i], resultHps[i + 6], battle.Initial.FriendMaxHPsEscort[i]); + } + + } + + + sbmaster.AppendLine(); + if (enemyescort != null) + sbmaster.AppendLine(ConstantsRes.BattleDetail_EnemyMainFleet); + else + sbmaster.AppendLine(ConstantsRes.BattleDetail_EnemyFleet); + + for (int i = 0; i < enemy.Count; i++) + { + IShipData? ship = enemy[i]; + if (ship == null) + continue; + + OutputResultData(sbmaster, i, + ship.MasterShip.NameWithClass, + battle.Initial.EnemyInitialHPs[i], resultHps[i + 12], battle.Initial.EnemyMaxHPs[i]); + } + + if (enemyescort != null) + { + sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); + + for (int i = 0; i < enemyescort.Count; i++) + { + IShipData? ship = enemyescort[i]; + if (ship == null) + continue; + + OutputResultData(sbmaster, i + 6, ship.MasterShip.NameWithClass, + battle.Initial.EnemyInitialHPsEscort[i], resultHps[i + 18], battle.Initial.EnemyMaxHPsEscort[i]); + } + } + + sbmaster.AppendLine(); + } + + return sbmaster.ToString(); + } + + private static string GetRangeString(int min, int max) => min != max ? $"{min} ~ {max}" : min.ToString(); + + private static void GetBattleDetailBaseAirCorps(StringBuilder sb, int mapAreaID) + { + foreach (BaseAirCorpsData corps in KCDatabase.Instance.BaseAirCorps.Values.Where(corps => corps.MapAreaID == mapAreaID)) + { + sb.AppendFormat("{0} [{1}] " + BattleRes.AirSuperiority + " {2}\r\n {3}\r\n", + corps.Name, Constants.GetBaseAirCorpsActionKind(corps.ActionKind), + GetRangeString(Calculator.GetAirSuperiority(corps, false), Calculator.GetAirSuperiority(corps, true)), + string.Join(", ", corps.Squadrons.Values + .Where(sq => sq.State == 1 && sq.EquipmentInstance != null) + .Select(sq => sq.EquipmentInstance.NameWithLevel))); + } + } + + private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseAirBattleBase p) + { + + if (p.IsStage1Available) + { + sb.Append("Stage 1: ").AppendLine(Constants.GetAirSuperiority(p.AirState)); + sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", + p.AircraftLostStage1Friend, p.AircraftTotalStage1Friend, + p.AircraftLostStage1Enemy, p.AircraftTotalStage1Enemy); + if (p.TouchAircraftFriend is not null) + sb.AppendFormat($" {BattleRes.Contact}: {{0}}\r\n", p.TouchAircraftFriend); + if (p.TouchAircraftEnemy is not null) + sb.AppendFormat($" {BattleRes.EnemyContact}: {{0}}\r\n", p.TouchAircraftEnemy); + } + if (p.IsStage2Available) + { + sb.Append("Stage 2: "); + if (p.IsAACutinAvailable) + { + sb.AppendFormat(BattleRes.AaciType, + p.AACutInShipName, + AntiAirCutIn.FromId(p.AACutInKind).EquipmentConditionsSingleLineDisplay(), + p.AACutInKind); + } + sb.AppendLine(); + sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", + p.AircraftLostStage2Friend, p.AircraftTotalStage2Friend, + p.AircraftLostStage2Enemy, p.AircraftTotalStage2Enemy); + } + + if (p.IsStage1Available || p.IsStage2Available) + sb.AppendLine(); + } + + + private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseBaseAirRaid p) + { + + if (p.IsStage1Available) + { + sb.Append("Stage 1: ").AppendLine(Constants.GetAirSuperiority(p.AirState)); + sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", + p.AircraftLostStage1Friend, p.AircraftTotalStage1Friend, + p.AircraftLostStage1Enemy, p.AircraftTotalStage1Enemy); + if (p.TouchAircraftFriend is not null) + sb.AppendFormat($" {BattleRes.Contact}: {{0}}\r\n", p.TouchAircraftFriend); + if (p.TouchAircraftEnemy is not null) + sb.AppendFormat($" {BattleRes.EnemyContact}: {{0}}\r\n", p.TouchAircraftEnemy); + } + if (p.IsStage2Available) + { + sb.Append("Stage 2: "); + if (p.IsAACutinAvailable) + { + sb.AppendFormat(BattleRes.AaciType, + p.AACutInShipName, + AntiAirCutIn.FromId(p.AACutInKind).EquipmentConditionsSingleLineDisplay(), + p.AACutInKind); + } + sb.AppendLine(); + sb.AppendFormat($" {BattleRes.Friendly}: -{{0}}/{{1}}\r\n {BattleRes.Enemy}: -{{2}}/{{3}}\r\n", + p.AircraftLostStage2Friend, p.AircraftTotalStage2Friend, + p.AircraftLostStage2Enemy, p.AircraftTotalStage2Enemy); + } + + if (p.IsStage1Available || p.IsStage2Available) + sb.AppendLine(); + } + + + private static void OutputFriendData(StringBuilder sb, IFleetData fleet, List initialHPs, List maxHPs) + { + + for (int i = 0; i < fleet.MembersInstance.Count; i++) + { + IShipData? ship = fleet.MembersInstance[i]; + + if (ship == null) + continue; + + sb.AppendFormat($"#{{0}}: {{1}} {{2}} " + + $"HP: {{3}} / {{4}} - " + + $"{GeneralRes.Firepower}:{{5}}, " + + $"{GeneralRes.Torpedo}:{{6}}, " + + $"{GeneralRes.AntiAir}:{{7}}, " + + $"{GeneralRes.Armor}:{{8}}{{9}}\r\n", + i + 1, + ship.MasterShip.ShipTypeName, ship.NameWithLevel, + initialHPs[i], maxHPs[i], + ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase, + fleet.EscapedShipList.Contains(ship.MasterID) ? $" ({BattleRes.Escaped})" : ""); + + sb.Append(" "); + sb.AppendLine(string.Join(", ", ship.AllSlotInstance.Zip( + ship.ExpansionSlot > 0 ? ship.Aircraft.Concat(new[] { 0 }) : ship.Aircraft, + (eq, aircraft) => eq == null ? null : ((eq.MasterEquipment.IsAircraft ? $"[{aircraft}] " : "") + eq.NameWithLevel) + ).Where(str => str != null))); + } + } + + private static void OutputFriendBase(StringBuilder sb, List initialHPs, List maxHPs) + { + + for (int i = 0; i < initialHPs.Count; i++) + { + if (maxHPs[i] <= 0) + continue; + + sb.AppendFormat(BattleRes.OutputFriendBase + "\r\n\r\n", + i + 1, + i + 1, + initialHPs[i], maxHPs[i]); + } + + } + + private static void OutputSupportData(StringBuilder sb, IFleetData fleet) + { + for (int i = 0; i < fleet.MembersInstance.Count; i++) + { + IShipData? ship = fleet.MembersInstance[i]; + + if (ship == null) + continue; + + sb.AppendFormat($"#{{0}}: {{1}} {{2}} - " + + $"{{3}} {GeneralRes.Firepower}, " + + $"{{4}} {GeneralRes.Torpedo}, " + + $"{{5}} {GeneralRes.AntiAir}, " + + $"{{6}} {GeneralRes.Armor}" + + $"\r\n", + i + 1, + ship.MasterShip.ShipTypeName, ship.NameWithLevel, + ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase); + + sb.Append(" "); + sb.AppendLine(string.Join(", ", ship.AllSlotInstance.Where(eq => eq != null))); + } + + } + + private static void OutputFriendlySupportData(StringBuilder sb, PhaseFriendlySupportInfo p) + { + + for (int i = 0; i < p.FleetsBeforePhase.FriendFleet.MembersInstance.Count; i++) + { + IShipData? ship = p.FleetsBeforePhase.FriendFleet.MembersInstance[i]; + + if (ship == null) + continue; + + sb.AppendFormat($"#{{0}}: {{1}} {{2}} " + + $"Lv. {{3}} " + + $"HP: {{4}} / {{5}} - " + + $"{GeneralRes.Firepower} {{6}}, " + + $"{GeneralRes.Torpedo} {{7}}, " + + $"{GeneralRes.AntiAir} {{8}}, " + + $"{GeneralRes.Armor} {{9}}" + + $"\r\n", + i + 1, + ship.MasterShip.ShipTypeName, ship.MasterShip.NameWithClass, ship.Level, + ship.HPCurrent, ship.HPMax, + ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase); + + sb.Append(" "); + sb.AppendLine(string.Join(", ", ship.AllSlotInstance + .OfType() + .Select(eq => eq.MasterEquipment.NameEN))); + } + } + + private static void OutputEnemyData(StringBuilder sb, List members, int[] levels, List initialHPs, int[] maxHPs, IEquipmentData?[][] slots, List> parameters) + { + + for (int i = 0; i < members.Count; i++) + { + if (members[i] == null) + continue; + + sb.AppendFormat("#{0}: ID:{1} {2} {3} Lv. {4} HP: {5} / {6}", + i + 1, + members[i].ShipID, + members[i].MasterShip.ShipTypeName, members[i].MasterShip.NameWithClass, + levels[i], + initialHPs[i], maxHPs[i]); + + if (parameters != null) + { + sb.AppendFormat($" - " + + $"{GeneralRes.Firepower}:{{0}}, " + + $"{GeneralRes.Torpedo}:{{1}}, " + + $"{GeneralRes.AntiAir}:{{2}}, " + + $"{GeneralRes.Armor}:{{3}}", + parameters[i][0], parameters[i][1], parameters[i][2], parameters[i][3]); + } + + sb.AppendLine().Append(" "); + sb.AppendLine(string.Join(", ", slots[i].Where(eq => eq != null))); + } + } + + + private static void OutputResultData(StringBuilder sb, int index, string name, int initialHP, int resultHP, int maxHP) + { + sb.AppendFormat("#{0}: {1} HP: ({2} → {3})/{4} ({5})\r\n", + index + 1, name, + Math.Max(initialHP, 0), + Math.Max(resultHP, 0), + Math.Max(maxHP, 0), + resultHP - initialHP); + } + + + private static string GetBattleResult(BattleManager bm) + { + BattleResult result = bm.Result; + + StringBuilder sb = new(); + + + sb.AppendLine(ConstantsRes.BattleDetail_Result); + sb.AppendFormat(ConstantsRes.BattleDetail_ResultRank + "\r\n", result.Rank); + + if (bm.IsCombinedBattle) + { + sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPMain + "\r\n", + result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.FriendFleet.MembersInstance[result.MvpIndex - 1].NameWithLevel); + sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPEscort + "\r\n", + result.MvpIndexCombined == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.EscortFleet.MembersInstance[result.MvpIndexCombined.Value - 1].NameWithLevel); + } + else + { + sb.AppendFormat("MVP: {0}\r\n", + result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.FriendFleet.MembersInstance[result.MvpIndex - 1].NameWithLevel); + } + + sb.AppendFormat(ConstantsRes.BattleDetail_AdmiralExp + "\r\n", result.AdmiralExp); + sb.AppendFormat(ConstantsRes.BattleDetail_ShipExp + "\r\n", result.BaseExp); + + if (!bm.IsPractice) + { + sb.AppendLine().AppendLine(ConstantsRes.BattleDetail_Drop); + + + int length = sb.Length; + + IShipDataMaster? ship = KCDatabase.Instance.MasterShips[(int?)result.DroppedShipId ?? -1]; + if (ship != null) + { + sb.AppendFormat(" {0} {1}\r\n", ship.ShipTypeName, ship.NameWithClass); + } + + IEquipmentDataMaster? eq = KCDatabase.Instance.MasterEquipments[result.DroppedEquipmentId ?? -1]; + if (eq != null) + { + sb.AppendFormat(" {0} {1}\r\n", eq.CategoryTypeInstance.NameEN, eq.NameEN); + } + + IUseItemMaster? item = KCDatabase.Instance.MasterUseItems[result.DroppedItemId ?? -1]; + if (item != null) + { + sb.Append(" ").AppendLine(item.NameTranslated); + } + + if (length == sb.Length) + { + sb.AppendLine(" (なし)"); + } + } + + + return sb.ToString(); + } + +} + diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index 339e2bba6..58d98e9f4 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -76,4 +76,10 @@ protected void EmulateBattle() FleetsAfterBattle = phase.EmulateBattle(FleetsAfterBattle, AttackDamages); } } + + public string GetBattleDetail(int index) + { + return string.Join(",", Phases + .Select(p => p.GetBattleDetail(index))); + } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs index 475a95554..00d91848b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs @@ -129,4 +129,9 @@ protected static List GetLaunchedShipIndex(List?> apiPlaneFrom, i .Select(i => i - 1) .ToList() ?? new(); + + public string GetBattleDetail(int index = -1) + { + return "Test"; + } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs index 133ebd4e1..acf2da2ef 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs @@ -108,7 +108,7 @@ public class PhaseBaseAirRaid : PhaseBase, IPhaseAirBattle public List EnemyHitFlags { get; set; } = new(); public List EnemyDamage { get; set; } = new(); - private List Squadrons { get; } + public List Squadrons { get; } public string Display { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs index f17c41770..6b01d7a85 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs @@ -18,15 +18,15 @@ public class PhaseFriendlyShelling : PhaseBase private ApiFriendlyBattle ApiFriendlyBattle { get; } private ApiHougeki ShellingData => ApiFriendlyBattle.ApiHougeki; - private int FlareIndexFriend { get; set; } - private int FlareIndexEnemy { get; set; } - private IShipData? FlareFriend { get; set; } - private IShipData? FlareEnemy { get; set; } - - private int SearchlightIndexFriend { get; set; } - private int SearchlightIndexEnemy { get; set; } - private IShipData? SearchlightFriend { get; set; } - private IShipData? SearchlightEnemy { get; set; } + public int FlareIndexFriend { get; private set; } + public int FlareIndexEnemy { get; private set; } + public IShipData? FlareFriend { get; private set; } + public IShipData? FlareEnemy { get; private set; } + + public int SearchlightIndexFriend { get; private set; } + public int SearchlightIndexEnemy { get; private set; } + public IShipData? SearchlightFriend { get; private set; } + public IShipData? SearchlightEnemy { get; private set; } public string InitialDisplay => GetDisplay(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index de83316ff..fe02aab00 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -45,6 +45,7 @@ public class PhaseInitial : PhaseBase public int[] EnemyMaxHPs => EnemyMembersInstance.Select(s => s?.HPMax ?? -1).ToArray(); public List> EnemyParameters { get; } public int[][] EnemySlots => EnemyMembersInstance.Select(s => s?.SlotInstance.Select(e => e?.EquipmentID ?? -1).ToArray() ?? []).ToArray(); + public IEquipmentData?[][] EnemySlotsInstance => EnemyMembersInstance.Select(s => s?.SlotInstance.ToArray() ?? []).ToArray(); [MemberNotNullWhen(true, nameof(EnemyMembersEscort))] [MemberNotNullWhen(true, nameof(EnemyLevelsEscort))] @@ -59,6 +60,7 @@ public class PhaseInitial : PhaseBase public int[]? EnemyMaxHPsEscort => EnemyMembersEscortInstance?.Select(s => s?.HPMax ?? -1).ToArray(); public List>? EnemyParametersEscort { get; } public int[][]? EnemySlotsEscort => EnemyMembersEscortInstance?.Select(s => s?.SlotInstance.Select(e => e?.EquipmentID ?? -1).ToArray() ?? []).ToArray(); + public IEquipmentData?[][]? EnemySlotsEscortInstance => EnemyMembersEscortInstance?.Select(s => s?.SlotInstance.ToArray() ?? []).ToArray(); private string PlayerMainFleetTitle => FleetsAfterPhase?.EscortFleet switch diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs index 0ca529ec4..ee5a7df9f 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightInitial.cs @@ -28,7 +28,7 @@ public class PhaseNightInitial : PhaseBase public int SearchlightIndexFriend { get; } public int SearchlightIndexEnemy { get; } - private IShipData? SearchlightFriend { get; } + public IShipData? SearchlightFriend { get; } public IShipData? SearchlightEnemy { get; } public IEquipmentData? SearchlightEquipmentFriend => GetSearchlight(SearchlightFriend); public IEquipmentData? SearchlightEquipmentEnemy => GetSearchlight(SearchlightEnemy); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs index f8ce46e74..24b88983e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs @@ -28,7 +28,7 @@ public class PhaseSupport : PhaseBase private List Damages { get; } private List Criticals { get; } private int SupportFleetId { get; } - private IFleetData? SupportFleet { get; set; } + public IFleetData? SupportFleet { get; private set; } public string? SupportFleetDisplay => CreateDisplay(); diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index ead5287ec..cc8663d21 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -229,7 +229,7 @@ private void ShowBattleDetail() BattleDetailView dialog = new(new BattleDetailViewModel { - BattleDetailText = "", // todo BattleDetailDescriptor.GetBattleDetail(bm), + BattleDetailText = BattleDetailDescriptor.GetBattleDetail(bm), }); dialog.Show(App.Current!.MainWindow!); @@ -1070,8 +1070,7 @@ void SetEnemyBackground(int index) bar.Value - bar.PrevValue, Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, isLandBase, isEscaped), attackDamages[refindex], - "" - // todo bd.GetBattleDetail(refindex) + bd.GetBattleDetail(refindex) ); bar.BackColor = isEscaped switch @@ -1111,8 +1110,7 @@ void SetEnemyBackground(int index) bar.MaximumValue, bar.Value - bar.PrevValue, Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase), - "" - // todo bd.GetBattleDetail(refindex) + bd.GetBattleDetail(refindex) ); } else @@ -1149,8 +1147,7 @@ void SetEnemyBackground(int index) bar.Value - bar.PrevValue, Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase, isEscaped), attackDamages[refindex], - "" - // todo bd.GetBattleDetail(refindex) + bd.GetBattleDetail(refindex) ); bar.BackColor = isEscaped switch @@ -1207,8 +1204,7 @@ void SetEnemyBackground(int index) bar.MaximumValue, bar.Value - bar.PrevValue, Constants.GetDamageState((double)bar.Value / bar.MaximumValue, isPractice, ship.MasterShip.IsLandBase), - "" - // todo bd.GetBattleDetail(refindex) + bd.GetBattleDetail(refindex) ); } else @@ -1251,7 +1247,7 @@ void SetEnemyBackground(int index) _ => EquipmentIconType.Unknown, }; - FleetFriendToolTip = FormBattle.SupportExpedition + "\r\n"; // todo + support.GetBattleDetail(); + FleetFriendToolTip = FormBattle.SupportExpedition + "\r\n" + support.GetBattleDetail(); FleetFriendText = ((isFriendCombined || hasFriend7thShip) && isEnemyCombined) switch { diff --git a/ElectronicObserverTypes/Mocks/EquipmentDataMock.cs b/ElectronicObserverTypes/Mocks/EquipmentDataMock.cs index 93cea55bf..6d8c94ac9 100644 --- a/ElectronicObserverTypes/Mocks/EquipmentDataMock.cs +++ b/ElectronicObserverTypes/Mocks/EquipmentDataMock.cs @@ -56,4 +56,6 @@ public void LoadFromResponse(string apiname, dynamic data) { throw new System.NotImplementedException(); } + + public override string ToString() => $"[{EquipmentID}] {Name}"; } From 7abdb5ab774156786a2eaacdf804138492a6b396 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Sun, 28 Jul 2024 20:44:45 +0900 Subject: [PATCH 04/38] fix battle detail --- ElectronicObserver/Services/ToolService.cs | 2 +- .../BattleDetail/BattleDetailDescriptor.cs | 40 ++++++++++--------- .../Sortie/Battle/BattleData.cs | 17 +++++--- .../Sortie/Battle/BattleIndex.cs | 1 + .../Phase/AirBaseRaidAttackViewModel.cs | 26 +++++++----- .../Battle/Phase/AirBattleAttackViewModel.cs | 24 ++++++----- .../Sortie/Battle/Phase/AttackPhaseBase.cs | 30 ++++++++++++++ .../Battle/Phase/AttackViewModelBase.cs | 18 +++++++++ .../Sortie/Battle/Phase/PhaseAirBattleBase.cs | 6 +-- .../Sortie/Battle/Phase/PhaseBase.cs | 15 +++---- .../Sortie/Battle/Phase/PhaseBaseAirRaid.cs | 24 +++++------ .../PhaseFriendNightBattleAttackViewModel.cs | 14 +++++-- .../Battle/Phase/PhaseFriendlyShelling.cs | 8 ++-- .../Sortie/Battle/Phase/PhaseNightBattle.cs | 8 ++-- .../Phase/PhaseNightBattleAttackViewModel.cs | 16 +++++--- .../Sortie/Battle/Phase/PhaseShelling.cs | 8 ++-- .../Phase/PhaseShellingAttackViewModel.cs | 14 +++++-- .../Sortie/Battle/Phase/PhaseSupport.cs | 22 +++++----- .../Phase/PhaseSupportAttackViewModel.cs | 12 ++++-- .../Sortie/Battle/Phase/PhaseTorpedo.cs | 4 +- .../Phase/PhaseTorpedoAttackViewModel.cs | 14 +++++-- .../SortieDetail/PhaseControl.xaml | 6 +-- 22 files changed, 209 insertions(+), 120 deletions(-) create mode 100644 ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs diff --git a/ElectronicObserver/Services/ToolService.cs b/ElectronicObserver/Services/ToolService.cs index 337ef9452..632948d00 100644 --- a/ElectronicObserver/Services/ToolService.cs +++ b/ElectronicObserver/Services/ToolService.cs @@ -439,7 +439,7 @@ private static string GetSmokerCsvLine(SortieDetailViewModel sortieDetail, Phase phaseTitle, attackDisplay.AttackKind, attackDisplay.WaveIndex.ToString(), - attackDisplay.AttackerName, + attackDisplay.AttackerDisplay, (attackDisplay.DefenderIndex.Index + 1).ToString(), attackDisplay.Defender.Name, attackDisplay.Defender.Level.ToString(), diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs index d23523b7b..8f2d9d237 100644 --- a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -314,20 +314,20 @@ void AppendEnemyFleetInfo(int[] members) } } - if (p.FlareFriend is not null) - { - sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", - p.FlareFriend.NameWithLevel, p.FlareIndexFriend + 1); - } + if (p.FlareFriend is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", + p.FlareFriend.NameWithLevel, p.FlareIndexFriend + 1); + } - if (p.FlareEnemy is not null) - { - sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", - p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexEnemy + 1); - } + if (p.FlareEnemy is not null) + { + sb.AppendFormat(ConstantsRes.BattleDetail_EnemyStarshell + "\r\n", + p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexEnemy + 1); + } - sb.AppendLine(); - break; + sb.AppendLine(); + break; case PhaseSearching p: @@ -396,11 +396,13 @@ void AppendEnemyFleetInfo(int[] members) GetBattleDetailPhaseAirBattle(sb, p); break; - } + case AttackPhaseBase attackPhase: + + sb.AppendLine(attackPhase.GetBattleDetail()); - if (!(phase is PhaseBaseAirAttack || phase is PhaseJetBaseAirAttack)) // 通常出力と重複するため - sb.Append(phase.GetBattleDetail()); + break; + } if (sb.Length > 0) { @@ -412,7 +414,7 @@ void AppendEnemyFleetInfo(int[] members) { sbmaster.AppendLine(ConstantsRes.BattleDetail_BattleEnd); - IFleetData? friend = battle.FleetsAfterBattle.FriendFleet; + IFleetData? friend = battle.FleetsAfterBattle.Fleet; IFleetData? friendescort = battle.FleetsAfterBattle.EscortFleet; List enemy = battle.Initial.EnemyMembersInstance; List? enemyescort = battle.Initial.EnemyMembersEscortInstance; @@ -745,14 +747,14 @@ private static string GetBattleResult(BattleManager bm) if (bm.IsCombinedBattle) { sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPMain + "\r\n", - result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.FriendFleet.MembersInstance[result.MvpIndex - 1].NameWithLevel); + result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex].NameWithLevel); sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPEscort + "\r\n", - result.MvpIndexCombined == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.EscortFleet.MembersInstance[result.MvpIndexCombined.Value - 1].NameWithLevel); + result.MvpIndexCombined == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.EscortFleet.MembersInstance[result.MvpIndexCombined.Value].NameWithLevel); } else { sb.AppendFormat("MVP: {0}\r\n", - result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.FriendFleet.MembersInstance[result.MvpIndex - 1].NameWithLevel); + result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex].NameWithLevel); } sb.AppendFormat(ConstantsRes.BattleDetail_AdmiralExp + "\r\n", result.AdmiralExp); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index 8b3460b3a..b2cb6744e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -83,9 +83,16 @@ protected void EmulateBattle() } } - public string GetBattleDetail(int index) - { - return string.Join(",", Phases - .Select(p => p.GetBattleDetail(index))); - } + public string GetBattleDetail(int index) => string.Join("\r\n", Phases + .OfType() + .Select(p => p.GetBattleDetail(index) switch + { + string detail => $""" + == {p.Title} == + {detail} + """, + + _ => null, + }) + .Where(d => !string.IsNullOrEmpty(d))); } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs index c1a45d76b..d1e128aa7 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleIndex.cs @@ -5,6 +5,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; public record BattleIndex(int Index, FleetFlag FleetFlag) { public string Display => $"#{Index + 1}"; + public bool IsFriend => FleetFlag is FleetFlag.Player; public int ToFlatIndex() => FleetFlag switch { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs index b9f6cdc7d..02f65ee74 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs @@ -9,23 +9,25 @@ public sealed class AirBaseRaidAttackViewModel : AttackViewModelBase { private int WaveIndex { get; } - public BattleIndex DefenderIndex { get; } - public IBaseAirCorpsData Defender { get; } - public int DefenderHpBeforeAttack { get; } - - private double Damage { get; } - private HitType HitType { get; } - private AirAttack AttackType { get; } - public string DamageDisplay { get; } - - public string AttackerName => (WaveIndex, DefenderIndex.FleetFlag) switch + public override BattleIndex? AttackerIndex => null; + public override string AttackerDisplay => (WaveIndex, DefenderIndex.FleetFlag) switch { - (> 0, _) => string.Format(BattleRes.AirSquadronWave, WaveIndex), + ( > 0, _) => string.Format(BattleRes.AirSquadronWave, WaveIndex), (_, FleetFlag.Player) => BattleRes.EnemyAirSquadron, (_, FleetFlag.Enemy) => BattleRes.FriendlyAirSquadron, _ => "???", }; + public override BattleIndex DefenderIndex { get; } + public IBaseAirCorpsData Defender { get; } + private int DefenderHpBeforeAttack { get; } + public override string DefenderDisplay { get; } + + private double Damage { get; } + private HitType HitType { get; } + private AirAttack AttackType { get; } + public override string DamageDisplay { get; } + public AirBaseRaidAttackViewModel(BattleFleets fleets, int waveIndex, AirBattleAttack attack) { WaveIndex = waveIndex; @@ -34,6 +36,8 @@ public AirBaseRaidAttackViewModel(BattleFleets fleets, int waveIndex, AirBattleA DefenderIndex = attack.Defenders.First().Defender; Defender = fleets.GetAirBase(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = attack.AttackType; DamageDisplay = diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs index 3e20356fa..c389242a7 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs @@ -9,25 +9,27 @@ public sealed class AirBattleAttackViewModel : AttackViewModelBase { public int WaveIndex { get; } - public BattleIndex DefenderIndex { get; } + public override BattleIndex? AttackerIndex => null; + public override string AttackerDisplay => (WaveIndex, DefenderIndex.FleetFlag) switch + { + ( > 0, _) => string.Format(BattleRes.AirSquadronWave, WaveIndex), + (_, FleetFlag.Player) => BattleRes.EnemyAirSquadron, + (_, FleetFlag.Enemy) => BattleRes.FriendlyAirSquadron, + _ => "???", + }; + + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } public int DefenderHpBeforeAttack { get; } + public override string DefenderDisplay { get; } public int Damage { get; } public HitType HitType { get; } public AirAttack AttackType { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + public override string DamageDisplay { get; } public bool GuardsFlagship { get; } - public string AttackerName => (WaveIndex, DefenderIndex.FleetFlag) switch - { - ( > 0, _) => string.Format(BattleRes.AirSquadronWave, WaveIndex), - (_, FleetFlag.Player) => BattleRes.EnemyAirSquadron, - (_, FleetFlag.Enemy) => BattleRes.FriendlyAirSquadron, - _ => "???", - }; - public string AttackKind => GetAttackKind(AttackType); public AirBattleAttackViewModel(BattleFleets fleets, int waveIndex, AirBattleAttack attack) @@ -38,6 +40,8 @@ public AirBattleAttackViewModel(BattleFleets fleets, int waveIndex, AirBattleAtt DefenderIndex = attack.Defenders.First().Defender; Defender = fleets.GetShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = attack.AttackType; GuardsFlagship = attack.Defenders.First().GuardsFlagship; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs new file mode 100644 index 000000000..a0db9a560 --- /dev/null +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using ElectronicObserver.Window.Dialog.BattleDetail; +using System.Linq; + +namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; + +public abstract class AttackPhaseBase : PhaseBase +{ + public abstract IEnumerable AttackDisplays { get; } + + private IEnumerable SearchBattleDetails(int index) => AttackDisplays + .Where(a => a.AttackerIndex?.ToFlatIndex() == index || a.DefenderIndex.ToFlatIndex() == index) + .Select(a => a.ToString()); + + public string? GetBattleDetail(int index = -1) + { + IEnumerable list = index switch + { + -1 => AttackDisplays.Select(d => d.ToString()), + _ => SearchBattleDetails(index), + }; + + if (list.Any()) + { + return string.Join("\r\n\r\n", list) + "\r\n"; + } + + return null; + } +} diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs index a822b205a..0bdaa1471 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs @@ -6,6 +6,19 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public abstract class AttackViewModelBase { + /// + /// null for unknown attacker index such as AB, support, air attack etc... + /// + public abstract BattleIndex? AttackerIndex { get; } + public abstract string AttackerDisplay { get; } + + public abstract BattleIndex DefenderIndex { get; } + public abstract string DefenderDisplay { get; } + + // \u2192 = → + public string AttackerDefenderDisplay => $"{AttackerDisplay} \u2192 {DefenderDisplay}"; + public abstract string DamageDisplay { get; } + protected static IEquipmentData? GetDamecon(IShipData ship) => ship.AllSlotInstance .FirstOrDefault(e => e?.MasterEquipment.CategoryType is EquipmentTypes.DamageControl); @@ -26,4 +39,9 @@ private static string HitDisplay(bool guardsFlagship, double damage) true => $"<{BattleRes.Protected}> ", _ => "", }; + + public override string ToString() => $""" + {AttackerDefenderDisplay} + {DamageDisplay} + """; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs index fdede952e..2e32083d7 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs @@ -13,7 +13,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseAirBattleBase : PhaseBase, IPhaseAirBattle +public class PhaseAirBattleBase : AttackPhaseBase, IPhaseAirBattle { public override string Title => BattleRes.BattlePhaseAirBattle; @@ -105,8 +105,8 @@ public class PhaseAirBattleBase : PhaseBase, IPhaseAirBattle public List LaunchedShipIndexFriend { get; } public List LaunchedShipIndexEnemy { get; } - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public string? Stage1Display { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs index 00d91848b..66146ca49 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBase.cs @@ -101,8 +101,8 @@ protected static List GetAttacks(FleetFlag fleetFlag, int index _ => AirAttack.None, }, - Defenders = new List - { + Defenders = + [ new() { Defender = new BattleIndex(t.Index, fleetFlag), @@ -117,9 +117,9 @@ protected static List GetAttacks(FleetFlag fleetFlag, int index }, RawDamage = t.Damage, }, - }, + ], }).ToList() - ?? new(); + ?? []; protected static List GetLaunchedShipIndex(List?> apiPlaneFrom, int index) => apiPlaneFrom @@ -128,10 +128,5 @@ protected static List GetLaunchedShipIndex(List?> apiPlaneFrom, i ?.Where(i => i > 0) .Select(i => i - 1) .ToList() - ?? new(); - - public string GetBattleDetail(int index = -1) - { - return "Test"; - } + ?? []; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs index acf2da2ef..0205964d5 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs @@ -13,7 +13,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseBaseAirRaid : PhaseBase, IPhaseAirBattle +public class PhaseBaseAirRaid : AttackPhaseBase, IPhaseAirBattle { public override string Title => BattleRes.BattlePhaseAirBaseRaid; @@ -69,8 +69,8 @@ public class PhaseBaseAirRaid : PhaseBase, IPhaseAirBattle public List LaunchedShipIndexFriend { get; } public List LaunchedShipIndexEnemy { get; } - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public string? Stage1Display { get; } @@ -98,15 +98,15 @@ public class PhaseBaseAirRaid : PhaseBase, IPhaseAirBattle public string? Stage2Display { get; protected set; } - public List PlayerTorpedoFlags { get; set; } = new(); - public List PlayerBomberFlags { get; set; } = new(); - public List PlayerHitFlags { get; set; } = new(); - public List PlayerDamage { get; set; } = new(); + public List PlayerTorpedoFlags { get; set; } = []; + public List PlayerBomberFlags { get; set; } = []; + public List PlayerHitFlags { get; set; } = []; + public List PlayerDamage { get; set; } = []; - public List EnemyTorpedoFlags { get; set; } = new(); - public List EnemyBomberFlags { get; set; } = new(); - public List EnemyHitFlags { get; set; } = new(); - public List EnemyDamage { get; set; } = new(); + public List EnemyTorpedoFlags { get; set; } = []; + public List EnemyBomberFlags { get; set; } = []; + public List EnemyHitFlags { get; set; } = []; + public List EnemyDamage { get; set; } = []; public List Squadrons { get; } @@ -146,7 +146,7 @@ public PhaseBaseAirRaid(ApiDestructionBattle battle, int waveIndex = 0) Equipment = KCDatabase.Instance.MasterEquipments[(int)b.ApiMstId], AircraftCount = b.ApiCount, }).ToList() - ?? new(); + ?? []; StringBuilder sb = new(); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs index 0f2b273f9..437924fdb 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs @@ -8,25 +8,31 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public sealed class PhaseFriendNightBattleAttackViewModel : AttackViewModelBase { - public BattleIndex AttackerIndex { get; } + public override BattleIndex AttackerIndex { get; } public IShipData Attacker { get; } public int AttackerHpBeforeAttack { get; } + public override string AttackerDisplay { get; } - public BattleIndex DefenderIndex { get; } + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } - public List DefenderHpBeforeAttacks { get; } = new(); + private List DefenderHpBeforeAttacks { get; } = []; + public override string DefenderDisplay { get; } private List Attacks { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + public override string DamageDisplay { get; } public PhaseFriendNightBattleAttackViewModel(BattleFleets fleets, BattleIndex attacker, BattleIndex defender, NightAttackKind attackType, List defenders) { AttackerIndex = attacker; Attacker = fleets.GetFriendShip(AttackerIndex)!; + AttackerDisplay = $"{Attacker.Name} {AttackerIndex.Display}"; + DefenderIndex = defender; Defender = fleets.GetFriendShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + Attacks = defenders .Select(d => new NightAttack { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs index 6b01d7a85..43c7aab97 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs @@ -10,7 +10,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseFriendlyShelling : PhaseBase +public class PhaseFriendlyShelling : AttackPhaseBase { public override string Title => BattleRes.BattlePhaseFriendlyShelling; @@ -30,8 +30,8 @@ public class PhaseFriendlyShelling : PhaseBase public string InitialDisplay => GetDisplay(); - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public PhaseFriendlyShelling(IKCDatabase kcDatabase, ApiFriendlyBattle apiFriendlyBattle) { @@ -141,7 +141,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List private string GetDisplay() { - List values = new(); + List values = []; if (SearchlightFriend is not null) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs index 57860ae4a..21985e83e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs @@ -9,13 +9,13 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseNightBattle : PhaseBase +public class PhaseNightBattle : AttackPhaseBase { public override string Title => BattleRes.BattlePhaseNightBattle; private IKCDatabase KcDatabase { get; } - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public PhaseNightBattle(IKCDatabase kcDatabase, List apiAtEflag, List apiAtList, List> apiClList, List> apiDamage, List> apiDfList, @@ -102,7 +102,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List 2 => new(attackerIndex + 6, FleetFlag.Player), _ => new(attackerIndex, FleetFlag.Player), }, - Defenders = new() { atk.Defenders[i] }, + Defenders = [atk.Defenders[i]], }; AttackDisplays.Add(new PhaseNightBattleAttackViewModel(FleetsAfterPhase, comboAttack, comboAttack.Defenders.First().Defender)); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs index 7ff8e6852..de78aef1f 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using ElectronicObserver.Data; using ElectronicObserverTypes; using ElectronicObserverTypes.Attacks; @@ -9,27 +8,34 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public sealed class PhaseNightBattleAttackViewModel : AttackViewModelBase { - public BattleIndex AttackerIndex { get; } + public override BattleIndex AttackerIndex { get; } public IShipData Attacker { get; } public int AttackerHpBeforeAttack { get; } + public override string AttackerDisplay { get; } - public BattleIndex DefenderIndex { get; } + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } - public List DefenderHpBeforeAttacks { get; } = new(); + public List DefenderHpBeforeAttacks { get; } = []; + public override string DefenderDisplay { get; } public NightAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + + public override string DamageDisplay { get; } public PhaseNightBattleAttackViewModel(BattleFleets fleets, PhaseNightBattleAttack attack, BattleIndex defenderIndex) { AttackerIndex = attack.Attacker; Attacker = fleets.GetShip(AttackerIndex)!; + AttackerDisplay = $"{Attacker.Name} {AttackerIndex.Display}"; + DefenderIndex = defenderIndex; Defender = fleets.GetShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = attack.AttackType; Attacks = attack.Defenders .Where(d => d.Defender == DefenderIndex) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs index 2eb8c584b..ff6812a0c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs @@ -9,7 +9,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseShelling : PhaseBase +public class PhaseShelling : AttackPhaseBase { public override string Title => DayShellingPhase switch { @@ -24,8 +24,8 @@ public class PhaseShelling : PhaseBase private ApiHougeki1 ShellingData { get; } public DayShellingPhase DayShellingPhase { get; } - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public PhaseShelling(IKCDatabase kcDatabase, ApiHougeki1 shellingData, DayShellingPhase dayShellingPhase) { @@ -97,7 +97,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List PhaseShellingAttack comboAttack = atk with { Attacker = new(attackers[i], FleetFlag.Player), - Defenders = new() { atk.Defenders[i] }, + Defenders = [atk.Defenders[i]], }; AttackDisplays.Add(new PhaseShellingAttackViewModel(FleetsAfterPhase, comboAttack)); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs index 7f19123dc..d0707b252 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs @@ -9,26 +9,32 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public sealed class PhaseShellingAttackViewModel : AttackViewModelBase { - public BattleIndex AttackerIndex { get; } + public override BattleIndex AttackerIndex { get; } public IShipData Attacker { get; } public int AttackerHpBeforeAttack { get; } + public override string AttackerDisplay { get; } - public BattleIndex DefenderIndex { get; } + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } - public List DefenderHpBeforeAttacks { get; } = new(); + public List DefenderHpBeforeAttacks { get; } = []; + public override string DefenderDisplay { get; } public DayAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + public override string DamageDisplay { get; } public PhaseShellingAttackViewModel(BattleFleets fleets, PhaseShellingAttack attack) { AttackerIndex = attack.Attacker; Attacker = fleets.GetShip(AttackerIndex)!; + AttackerDisplay = $"{Attacker.Name} {AttackerIndex.Display}"; + DefenderIndex = attack.Defenders.First().Defender; Defender = fleets.GetShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = ProcessAttack(Attacker, Defender, attack.AttackType); Attacks = attack.Defenders .Select(d => new DayAttack diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs index 24b88983e..e396f8a7c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupport.cs @@ -8,7 +8,7 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public class PhaseSupport : PhaseBase +public class PhaseSupport : AttackPhaseBase { public override string Title => IsNightSupport switch { @@ -32,8 +32,8 @@ public class PhaseSupport : PhaseBase public string? SupportFleetDisplay => CreateDisplay(); - private List Attacks { get; } = new(); - public List AttackDisplays { get; } = new(); + private List Attacks { get; } = []; + public override List AttackDisplays { get; } = []; public PhaseSupport(SupportType supportFlag, ApiSupportInfo apiSupportInfo, bool isNightSupport) { @@ -54,7 +54,7 @@ ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 ApiSupportHourai attack => attack.ApiDamage, - _ => new(), + _ => [], }; Criticals = SupportAttack(supportFlag, apiSupportInfo) switch @@ -68,7 +68,7 @@ ApiSupportAiratack attack when attack.ApiStageFlag[2] is not 0 ApiSupportHourai attack => attack.ApiClList, - _ => new(), + _ => [], }; SupportFleetId = SupportAttack(supportFlag, apiSupportInfo) switch @@ -108,15 +108,15 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List Attacks.Add(new() { AttackType = SupportFlag, - Defenders = new() - { + Defenders = + [ new() { Defender = new(i, FleetFlag.Enemy), RawDamage = Damages[i], CriticalFlag = Criticals[i], }, - }, + ], }); } @@ -131,15 +131,15 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List Attacks.Add(new() { AttackType = SupportFlag, - Defenders = new() - { + Defenders = + [ new() { Defender = new(i + 6, FleetFlag.Enemy), RawDamage = Damages[i + 6], CriticalFlag = Criticals[i + 6], }, - }, + ], }); } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs index 6d2aa7cdc..8d28d15e1 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs @@ -7,21 +7,25 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public sealed class PhaseSupportAttackViewModel : AttackViewModelBase { - public string Attacker => BattleRes.SupportFleet; + public override BattleIndex? AttackerIndex => null; + public override string AttackerDisplay => BattleRes.SupportFleet; - public BattleIndex DefenderIndex { get; } + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } - public List DefenderHpBeforeAttacks { get; } = new(); + private List DefenderHpBeforeAttacks { get; } = []; + public override string DefenderDisplay { get; } private SupportType AttackType { get; } private List Attacks { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + public override string DamageDisplay { get; } public PhaseSupportAttackViewModel(BattleFleets fleets, PhaseSupportAttack attack) { DefenderIndex = attack.Defenders.First().Defender; Defender = fleets.GetShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = attack.AttackType; Attacks = attack.Defenders .Select(d => new SupportAttack diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedo.cs index 09899b1ae..e01c9bcdf 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedo.cs @@ -6,9 +6,9 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; -public abstract class PhaseTorpedo : PhaseBase +public abstract class PhaseTorpedo : AttackPhaseBase { - public List AttackDisplays { get; } = []; + public override List AttackDisplays { get; } = []; protected static PhaseTorpedoAttack MakeAttack(int attackerIndex, int targetIndex, FleetFlag fleetFlag, List targets, List damages, List attackDamages, List criticalFlags) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs index 929691e86..eb03c666c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs @@ -9,25 +9,31 @@ namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase public sealed class PhaseTorpedoAttackViewModel : AttackViewModelBase { - public BattleIndex AttackerIndex { get; } + public override BattleIndex AttackerIndex { get; } public IShipData Attacker { get; } public int AttackerHpBeforeAttack { get; } + public override string AttackerDisplay { get; } - public BattleIndex DefenderIndex { get; } + public override BattleIndex DefenderIndex { get; } public IShipData Defender { get; } - public List DefenderHpBeforeAttacks { get; } = new(); + private List DefenderHpBeforeAttacks { get; } = []; + public override string DefenderDisplay { get; } private DayAttackKind AttackType { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } - public string DamageDisplay { get; } + public override string DamageDisplay { get; } public PhaseTorpedoAttackViewModel(BattleFleets fleets, PhaseTorpedoAttack attack) { AttackerIndex = attack.Attacker; Attacker = fleets.GetShip(AttackerIndex)!; + AttackerDisplay = $"{Attacker.Name} {AttackerIndex.Display}"; + DefenderIndex = attack.Defenders.First().Defender; Defender = fleets.GetShip(DefenderIndex)!; + DefenderDisplay = $"{Defender.Name} {DefenderIndex.Display}"; + AttackType = ProcessAttack(Attacker, Defender, attack.AttackType); Attacks = attack.Defenders .Select(d => new DayAttack diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieDetail/PhaseControl.xaml b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieDetail/PhaseControl.xaml index 48422bae8..8929a3b5e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieDetail/PhaseControl.xaml +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/SortieDetail/PhaseControl.xaml @@ -80,7 +80,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -104,7 +104,7 @@ - + From aa71f860e73a07c87f7196ac9d8d83d81ae60915 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Tue, 30 Jul 2024 14:08:51 +0900 Subject: [PATCH 05/38] implement missing battle handling --- .../Data/Battle/BattleManager.cs | 268 ++++++++++-------- 1 file changed, 154 insertions(+), 114 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 01b3398f8..a2ed7a0db 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -9,6 +9,7 @@ using ElectronicObserver.KancolleApi.Types; using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.SpMidnight; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Airbattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battleresult; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.BattleWater; @@ -16,6 +17,7 @@ using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EachBattleWater; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcBattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcMidnightBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcNightToDay; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdAirbattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdShooting; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.MidnightBattle; @@ -25,11 +27,13 @@ using ElectronicObserver.KancolleApi.Types.ApiReqMap.Start; using ElectronicObserver.KancolleApi.Types.ApiReqPractice.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqPractice.BattleResult; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.MidnightBattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Airbattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battleresult; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdAirbattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdShooting; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.NightToDay; using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.Resource.Record; using ElectronicObserver.Utility.Mathematics; @@ -50,7 +54,7 @@ namespace ElectronicObserver.Data.Battle; public class BattleManager : APIWrapper { - public static readonly string BattleLogPath = "BattleLog"; + public static string BattleLogPath => "BattleLog"; public delegate void ShipLevelUpHandler(IShipData ship, int nextLevel); @@ -59,17 +63,17 @@ public class BattleManager : APIWrapper ///
/// /// - public event ShipLevelUpHandler ShipLevelUp; + public event ShipLevelUpHandler? ShipLevelUp; /// /// 羅針盤データ /// - public CompassData Compass { get; private set; } + public CompassData? Compass { get; private set; } /// /// 昼戦データ /// - public FirstBattleData BattleDay { get; private set; } + public FirstBattleData? BattleDay { get; private set; } /// /// 夜戦データ @@ -79,17 +83,17 @@ public class BattleManager : APIWrapper /// /// 戦闘結果データ /// - public BattleResult Result { get; private set; } + public BattleResult? Result { get; private set; } /// /// The battle result api doesn't report SS, so we need to evaluate it manually. /// - public string PredictedBattleRank { get; set; } + public string? PredictedBattleRank { get; set; } // In the api, heavy base air raid is implemented as 3 different air raid battles // If we decide to collapse it down into 1 battle, this should be deleted // and heavy base air raid moved to BattleDay like regular BattleBaseAirRaid - public List HeavyBaseAirRaids { get; } = new(); + public List HeavyBaseAirRaids { get; } = []; [Flags] public enum BattleModes @@ -113,7 +117,7 @@ public enum BattleModes /// /// 戦闘種別 /// - public BattleModes BattleMode { get; private set; } + public BattleModes BattleMode { get; } /// @@ -168,7 +172,7 @@ public bool StartsFromNightBattle /// /// 2回目の戦闘 /// - public BattleData? SecondBattle => StartsFromDayBattle ? (BattleData)BattleNight : BattleDay; + public BattleData? SecondBattle => StartsFromDayBattle ? BattleNight : BattleDay; /// @@ -267,13 +271,11 @@ public override void LoadFromResponse(string apiname, dynamic data) BattleDay = null; BattleNight = null; Result = null; - BattleMode = BattleModes.Undefined; Compass = new CompassData(); Compass.LoadFromResponse(apiname, data); if (apiData is ApiReqMapNextResponse { ApiDestructionBattle: { } battle }) { - BattleMode = BattleModes.BaseAirRaid; BattleDay = BattleFactory.CreateBattle(battle, Fleets); BattleFinished(); } @@ -299,7 +301,6 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqSortieBattleResponse battle) break; - BattleMode = BattleModes.Normal; BattleDay = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -308,114 +309,149 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqBattleMidnightBattleResponse battle) break; - BattleNight = BattleFactory.CreateBattle(battle, BattleDay.FleetsAfterBattle); + BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); } break; - /* case "api_req_battle_midnight/sp_midnight": - BattleMode = BattleModes.NightOnly; - BattleDay = null; - BattleNight = new BattleNightOnly(); - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqBattleMidnightSpMidnightResponse battle) break; + + BattleNight = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_sortie/airbattle": - BattleMode = BattleModes.AirBattle; - BattleDay = new BattleAirBattle(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqSortieAirbattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_sortie/ld_airbattle": - BattleMode = BattleModes.AirRaid; - BattleDay = new BattleAirRaid(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqSortieLdAirbattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_sortie/night_to_day": - BattleMode = BattleModes.NightDay; - BattleNight = new BattleNormalDayFromNight(); - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqSortieNightToDayResponse battle) break; + + // todo + // BattleNight = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_sortie/ld_shooting": - BattleMode = BattleModes.Radar; - BattleDay = new BattleNormalRadar(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqSortieLdShootingResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/battle": - BattleMode = BattleModes.Normal | BattleModes.CombinedTaskForce; - BattleDay = new BattleCombinedNormalDay(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleBattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/midnight_battle": - BattleNight = new BattleCombinedNormalNight(); - //BattleNight.TakeOverParameters( BattleDay ); //checkme: 連合艦隊夜戦では昼戦での与ダメージがMVPに反映されない仕様? - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleMidnightBattleResponse battle) break; + + BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + } + break; case "api_req_combined_battle/sp_midnight": - BattleMode = BattleModes.NightOnly | BattleModes.CombinedMask; + { + if (apiData is not ApiReqCombinedBattleSpMidnightResponse battle) break; + BattleDay = null; - BattleNight = new BattleCombinedNightOnly(); - BattleNight.LoadFromResponse(apiname, data); - break; + BattleNight = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/airbattle": - BattleMode = BattleModes.AirBattle | BattleModes.CombinedTaskForce; - BattleDay = new BattleCombinedAirBattle(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleAirbattleResponse battle) break; + + // todo + // BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/battle_water": - BattleMode = BattleModes.Normal | BattleModes.CombinedSurface; - BattleDay = new BattleCombinedWater(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleBattleWaterResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/ld_airbattle": - BattleMode = BattleModes.AirRaid | BattleModes.CombinedTaskForce; - BattleDay = new BattleCombinedAirRaid(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleLdAirbattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/ec_battle": - BattleMode = BattleModes.Normal | BattleModes.EnemyCombinedFleet; - BattleDay = new BattleEnemyCombinedDay(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleEcBattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/ec_midnight_battle": - BattleNight = new BattleEnemyCombinedNight(); - BattleNight.TakeOverParameters(BattleDay); - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleEcMidnightBattleResponse battle) break; + + BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + } + break; case "api_req_combined_battle/ec_night_to_day": - BattleMode = BattleModes.NightDay | BattleModes.EnemyCombinedFleet; - BattleNight = new BattleEnemyCombinedDayFromNight(); - BattleNight.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleEcNightToDayResponse battle) break; + + // todo + // BattleNight = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/each_battle": - BattleMode = BattleModes.Normal | BattleModes.CombinedTaskForce | BattleModes.EnemyCombinedFleet; - BattleDay = new BattleCombinedEachDay(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleEachBattleResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/each_battle_water": - BattleMode = BattleModes.Normal | BattleModes.CombinedSurface | BattleModes.EnemyCombinedFleet; - BattleDay = new BattleCombinedEachWater(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleEachBattleWaterResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_combined_battle/ld_shooting": - BattleMode = BattleModes.Radar | BattleModes.CombinedTaskForce; - BattleDay = new BattleCombinedRadar(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqCombinedBattleLdShootingResponse battle) break; + + BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_member/get_practice_enemyinfo": EnemyAdmiralName = data.api_nickname; @@ -423,17 +459,22 @@ public override void LoadFromResponse(string apiname, dynamic data) break; case "api_req_practice/battle": - BattleMode = BattleModes.Practice; - BattleDay = new BattlePracticeDay(); - BattleDay.LoadFromResponse(apiname, data); - break; + { + if (apiData is not ApiReqPracticeBattleResponse battle) break; + + // todo + // BattleDay = BattleFactory.CreateBattle(battle, Fleets); + } + break; case "api_req_practice/midnight_battle": - BattleNight = new BattlePracticeNight(); - BattleNight.TakeOverParameters(BattleDay); - BattleNight.LoadFromResponse(apiname, data); - break; - */ + { + if (apiData is not ApiReqPracticeMidnightBattleResponse battle) break; + + // todo + // BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + } + break; case "api_req_sortie/battleresult": case "api_req_combined_battle/battleresult": @@ -455,7 +496,6 @@ public override void LoadFromResponse(string apiname, dynamic data) BattleDay = null; BattleNight = null; Result = null; - BattleMode = BattleModes.Undefined; PredictedBattleRank = ""; DroppedShipCount = DroppedEquipmentCount = 0; DroppedItemCount.Clear(); @@ -785,34 +825,34 @@ public int PredictWinRank(out double friendrate, out double enemyrate) /// public bool WillNightBattleWithMainFleet() { - if (StartsFromDayBattle && IsEnemyCombined) + if (!IsEnemyCombined) return false; // ? true? + + var initial = BattleDay.Initial; + int score = 0; + for (int i = 0; i < initial.EnemyInitialHPsEscort.Count; i++) { - var initial = BattleDay.Initial; - int score = 0; - for (int i = 0; i < initial.EnemyInitialHPsEscort.Count; i++) + if (initial.EnemyMembersEscort.ToList()[i] > 0) { - if (initial.EnemyMembersEscort.ToList()[i] > 0) - { - double rate = (double)BattleDay.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / initial.EnemyMaxHPsEscort.ToList()[i]; + double rate = (double)BattleDay.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / + initial.EnemyMaxHPsEscort.ToList()[i]; - if (rate > 0.5) - { - score += 10; - } - else if (rate > 0.25) - { - score += 7; - } + if (rate > 0.5) + { + score += 10; + } + else if (rate > 0.25) + { + score += 7; + } - if (i == 0 && rate > 0) - { - score += 10; - } + if (i == 0 && rate > 0) + { + score += 10; } } - return score < 30; } - else return false; // ? true? + + return score < 30; } From 86cf0b06e468b0b30804e511cd3710f4888ac079 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Wed, 31 Jul 2024 14:42:22 +0900 Subject: [PATCH 06/38] adjustments --- .../Data/Battle/BattleManager.cs | 131 +++++++----------- .../Sortie/Battle/BattleFactory.cs | 8 ++ .../Sortie/Node/BattleResult.cs | 12 ++ .../Window/Wpf/Battle/BattleView.xaml.cs | 5 +- .../Window/Wpf/Battle/BattleViewModel.cs | 58 ++++---- .../InformationView/InformationViewModel.cs | 2 +- 6 files changed, 100 insertions(+), 116 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index a2ed7a0db..5f3df545d 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Linq; using System.Text.Json; using CommunityToolkit.Mvvm.DependencyInjection; -using ElectronicObserver.Database.KancolleApi; -using ElectronicObserver.KancolleApi.Types; using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.SpMidnight; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Airbattle; @@ -22,7 +20,6 @@ using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdShooting; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.MidnightBattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.SpMidnight; -using ElectronicObserver.KancolleApi.Types.ApiReqMap.Models; using ElectronicObserver.KancolleApi.Types.ApiReqMap.Next; using ElectronicObserver.KancolleApi.Types.ApiReqMap.Start; using ElectronicObserver.KancolleApi.Types.ApiReqPractice.Battle; @@ -38,7 +35,6 @@ using ElectronicObserver.Resource.Record; using ElectronicObserver.Utility.Mathematics; using ElectronicObserver.Window.Dialog.QuestTrackerManager.Enums; -using ElectronicObserver.Window.Tools.SortieRecordViewer; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; @@ -73,12 +69,12 @@ public class BattleManager : APIWrapper /// /// 昼戦データ /// - public FirstBattleData? BattleDay { get; private set; } + public FirstBattleData? FirstBattle { get; private set; } /// /// 夜戦データ /// - public BattleData? BattleNight { get; private set; } + public BattleData? SecondBattle { get; private set; } /// /// 戦闘結果データ @@ -120,23 +116,6 @@ public enum BattleModes public BattleModes BattleMode { get; } - /// - /// 昼戦から開始する戦闘かどうか - /// - public bool StartsFromDayBattle => !StartsFromNightBattle; - - /// - /// 夜戦から開始する戦闘かどうか - /// - public bool StartsFromNightBattle - { - get - { - var phase = BattleMode & BattleModes.BattlePhaseMask; - return phase == BattleModes.NightOnly || phase == BattleModes.NightDay; - } - } - /// /// 連合艦隊戦かどうか /// @@ -145,7 +124,7 @@ public bool StartsFromNightBattle /// /// 演習かどうか /// - public bool IsPractice => (BattleMode & BattleModes.BattlePhaseMask) == BattleModes.Practice; + public bool IsPractice => FirstBattle is BattlePracticeDay; /// /// 敵が連合艦隊かどうか @@ -157,24 +136,6 @@ public bool StartsFromNightBattle /// public bool IsBaseAirRaid => (BattleMode & BattleModes.BattlePhaseMask) == BattleModes.BaseAirRaid; - - /// - /// 1回目の戦闘 - /// - public FirstBattleData FirstBattle => HeavyBaseAirRaids switch - { - // first battle gets used for things like engagement - // remove this part if heavy air raids get moved to BattleDay - { Count: > 0 } => HeavyBaseAirRaids.Last(), - _ => StartsFromDayBattle ? BattleDay : (FirstBattleData)BattleNight! - }; - - /// - /// 2回目の戦闘 - /// - public BattleData? SecondBattle => StartsFromDayBattle ? BattleNight : BattleDay; - - /// /// 出撃中に入手した艦船数 /// @@ -268,23 +229,23 @@ public override void LoadFromResponse(string apiname, dynamic data) case "api_req_map/start": case "api_req_map/next": { - BattleDay = null; - BattleNight = null; + FirstBattle = null; + SecondBattle = null; Result = null; Compass = new CompassData(); Compass.LoadFromResponse(apiname, data); if (apiData is ApiReqMapNextResponse { ApiDestructionBattle: { } battle }) { - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); BattleFinished(); } } break; - /* + case "api_req_map/air_raid": { - BattleMode = BattleModes.BaseAirRaid; + /* todo // BattleDay = new BattleHeavyBaseAirRaid(); // BattleDay.LoadFromResponse(apiname, data.api_destruction_battle[0]); foreach (dynamic airraid in data.api_destruction_battle) @@ -294,14 +255,15 @@ public override void LoadFromResponse(string apiname, dynamic data) HeavyBaseAirRaids.Add(raid); } BattleFinished(); + */ } break; - */ + case "api_req_sortie/battle": { if (apiData is not ApiReqSortieBattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -309,7 +271,9 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqBattleMidnightBattleResponse battle) break; - BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + Debug.Assert(FirstBattle is not null); + + SecondBattle = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); } break; @@ -317,7 +281,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqBattleMidnightSpMidnightResponse battle) break; - BattleNight = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -325,7 +289,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqSortieAirbattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -333,7 +297,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqSortieLdAirbattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -350,7 +314,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqSortieLdShootingResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -358,7 +322,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleBattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -366,7 +330,9 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleMidnightBattleResponse battle) break; - BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + Debug.Assert(FirstBattle is not null); + + SecondBattle = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); } break; @@ -374,8 +340,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleSpMidnightResponse battle) break; - BattleDay = null; - BattleNight = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -392,7 +357,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleBattleWaterResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -400,7 +365,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleLdAirbattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -408,7 +373,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleEcBattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -416,7 +381,9 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleEcMidnightBattleResponse battle) break; - BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + Debug.Assert(FirstBattle is not null); + + SecondBattle = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); } break; @@ -433,7 +400,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleEachBattleResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -441,7 +408,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleEachBattleWaterResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -449,7 +416,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleLdShootingResponse battle) break; - BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -462,8 +429,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqPracticeBattleResponse battle) break; - // todo - // BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -471,8 +437,9 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqPracticeMidnightBattleResponse battle) break; - // todo - // BattleNight = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); + Debug.Assert(FirstBattle is not null); + + SecondBattle = BattleFactory.CreateBattle(battle, FirstBattle.FleetsAfterBattle); } break; @@ -480,12 +447,12 @@ public override void LoadFromResponse(string apiname, dynamic data) case "api_req_combined_battle/battleresult": case "api_req_practice/battle_result": { - if (apiData is not ISortieBattleResultApi result) break; - - Result = result switch + Result = apiData switch { - ApiReqCombinedBattleBattleresultResponse r => new(r), - _ => new(result), + ApiReqCombinedBattleBattleresultResponse c => new(c), + ISortieBattleResultApi s => new(s), + ApiReqPracticeBattleResultResponse p => new(p), + _ => null, }; BattleFinished(); break; @@ -493,8 +460,8 @@ public override void LoadFromResponse(string apiname, dynamic data) case "api_port/port": Compass = null; - BattleDay = null; - BattleNight = null; + FirstBattle = null; + SecondBattle = null; Result = null; PredictedBattleRank = ""; DroppedShipCount = DroppedEquipmentCount = 0; @@ -565,11 +532,11 @@ private void BattleFinished() } else if (IsBaseAirRaid) { - if (BattleDay is BattleBaseAirRaid raid) + if (FirstBattle is BattleBaseAirRaid raid) { PhaseBaseAirRaid? airraid = raid.BaseAirRaid; - List initialHPs = BattleDay.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); - int damage = initialHPs.Zip(BattleDay.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); + List initialHPs = FirstBattle.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); + int damage = initialHPs.Zip(FirstBattle.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedBaseAirRaid, @@ -827,13 +794,13 @@ public bool WillNightBattleWithMainFleet() { if (!IsEnemyCombined) return false; // ? true? - var initial = BattleDay.Initial; + var initial = FirstBattle.Initial; int score = 0; for (int i = 0; i < initial.EnemyInitialHPsEscort.Count; i++) { if (initial.EnemyMembersEscort.ToList()[i] > 0) { - double rate = (double)BattleDay.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / + double rate = (double)FirstBattle.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / initial.EnemyMaxHPsEscort.ToList()[i]; if (rate > 0.5) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs index 5e0053ae3..47be82cfb 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs @@ -11,6 +11,8 @@ using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.MidnightBattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.SpMidnight; using ElectronicObserver.KancolleApi.Types.ApiReqMap.Models; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.Battle; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.MidnightBattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Airbattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdAirbattle; @@ -92,4 +94,10 @@ public BattleCombinedEachDay CreateBattle(OpeningTorpedoRework_ApiReqCombinedBat public BattleCombinedEachWater CreateBattle(OpeningTorpedoRework_ApiReqCombinedBattleEachBattleWaterResponse battle, BattleFleets fleets) => new(PhaseFactory, fleets, battle); + + public BattlePracticeDay CreateBattle(ApiReqPracticeBattleResponse battle, BattleFleets fleets) + => new(PhaseFactory, fleets, battle); + + public BattlePracticeNight CreateBattle(ApiReqPracticeMidnightBattleResponse battle, BattleFleets fleets) + => new(PhaseFactory, fleets, battle); } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs index 2c156ea20..ea6565cd8 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleResult.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battleresult; +using ElectronicObserver.KancolleApi.Types.ApiReqPractice.BattleResult; using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.KancolleApi.Types.Models; using ElectronicObserverTypes; @@ -62,4 +63,15 @@ public BattleResult(ApiReqCombinedBattleBattleresultResponse result) ExpListCombined = result.ApiGetShipExpCombined; LevelUpListCombined = result.ApiGetExpLvupCombined; } + + public BattleResult(ApiReqPracticeBattleResultResponse result) + { + Rank = result.ApiWinRank; + AdmiralExp = result.ApiGetExp; + MvpIndex = result.ApiMvp - 1; + BaseExp = result.ApiGetBaseExp; + ExpList = result.ApiGetShipExp; + LevelUpList = result.ApiGetExpLvup; + EnemyFleetName = result.ApiEnemyInfo.ApiDeckName; + } } diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleView.xaml.cs b/ElectronicObserver/Window/Wpf/Battle/BattleView.xaml.cs index eacee4bc2..e74dc5360 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleView.xaml.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleView.xaml.cs @@ -27,9 +27,6 @@ public BattleView() // not really sure how to do this mvvm style private void FrameworkElement_OnContextMenuOpening(object sender, ContextMenuEventArgs e) { - var bm = KCDatabase.Instance.Battle; - - if (bm == null || bm.BattleMode == BattleManager.BattleModes.Undefined) - e.Handled = true; + e.Handled = KCDatabase.Instance.Battle.FirstBattle is null; } } diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index cc8663d21..8a8f62803 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -225,7 +225,7 @@ private void ShowBattleDetail() { BattleManager? bm = KCDatabase.Instance.Battle; - if (bm == null || bm.BattleMode == BattleManager.BattleModes.Undefined) return; + if (bm.FirstBattle is null) return; BattleDetailView dialog = new(new BattleDetailViewModel { @@ -267,8 +267,8 @@ private void Updated(string apiname, dynamic data) SetFormation(bm); ClearSearchingResult(); ClearBaseAirAttack(); - SetAerialWarfare(null, ((BattleBaseAirRaid)bm.BattleDay).BaseAirRaid); - SetHPBar(bm.BattleDay); + SetAerialWarfare(null, ((BattleBaseAirRaid)bm.FirstBattle).BaseAirRaid); + SetHPBar(bm.FirstBattle); SetDamageRate(bm); ViewVisible = !hideDuringBattle; @@ -300,19 +300,19 @@ private void Updated(string apiname, dynamic data) { SetFormation(bm); - SetSearchingResult(bm.BattleDay); + SetSearchingResult(bm.FirstBattle); - if (bm.BattleDay is IBaseAirAttack baa) + if (bm.FirstBattle is IBaseAirAttack baa) { SetBaseAirAttack(baa.BaseAirAttack); } - if (bm.BattleDay is IAirBattle ab) + if (bm.FirstBattle is IAirBattle ab) { SetAerialWarfare(ab.JetAirBattle, ab.AirBattle); } - SetHPBar(bm.BattleDay); + SetHPBar(bm.FirstBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -324,10 +324,10 @@ private void Updated(string apiname, dynamic data) case "api_req_battle_midnight/battle": case "api_req_practice/midnight_battle": { - if (bm.BattleNight is not INightInitial b) return; + if (bm.SecondBattle is not INightInitial b) return; SetNightBattleEvent(b.NightInitial); - SetHPBar(bm.BattleNight); + SetHPBar(bm.SecondBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -338,14 +338,14 @@ private void Updated(string apiname, dynamic data) case "api_req_battle_midnight/sp_midnight": { - if (bm.BattleNight is not INightInitial b) return; + if (bm.FirstBattle is not INightInitial b) return; SetFormation(bm); ClearBaseAirAttack(); ClearAerialWarfare(); ClearSearchingResult(); SetNightBattleEvent(b.NightInitial); - SetHPBar(bm.BattleNight); + SetHPBar(bm.FirstBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -356,7 +356,7 @@ private void Updated(string apiname, dynamic data) case "api_req_sortie/airbattle": { - if (bm.BattleDay is not BattleAirBattle bab) return; + if (bm.FirstBattle is not BattleAirBattle bab) return; SetFormation(bm); SetSearchingResult(bab); @@ -373,7 +373,7 @@ private void Updated(string apiname, dynamic data) case "api_req_sortie/night_to_day": { - if (bm.BattleNight is not BattleNormalDayFromNight battle) return; + if (bm.FirstBattle is not BattleNormalDayFromNight battle) return; SetFormation(bm); ClearAerialWarfare(); @@ -388,7 +388,7 @@ private void Updated(string apiname, dynamic data) SetAerialWarfare(battle.JetAirBattle, battle.AirBattle); } - SetHPBar(bm.BattleDay); + SetHPBar(bm.FirstBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -407,19 +407,19 @@ private void Updated(string apiname, dynamic data) { SetFormation(bm); - SetSearchingResult(bm.BattleDay); + SetSearchingResult(bm.FirstBattle); - if (bm.BattleDay is IBaseAirAttack baa) + if (bm.FirstBattle is IBaseAirAttack baa) { SetBaseAirAttack(baa.BaseAirAttack); } - if (bm.BattleDay is IAirBattle ab) + if (bm.FirstBattle is IAirBattle ab) { SetAerialWarfare(ab.JetAirBattle, ab.AirBattle); } - SetHPBar(bm.BattleDay); + SetHPBar(bm.FirstBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -430,7 +430,7 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/airbattle": { - if (bm.BattleDay is not BattleCombinedAirBattle bcab) return; + if (bm.FirstBattle is not BattleCombinedAirBattle bcab) return; SetFormation(bm); SetSearchingResult(bcab); @@ -448,10 +448,10 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/midnight_battle": case "api_req_combined_battle/ec_midnight_battle": { - if (bm.BattleNight is not INightInitial b) break; + if (bm.SecondBattle is not INightInitial b) break; SetNightBattleEvent(b.NightInitial); - SetHPBar(bm.BattleNight); + SetHPBar(bm.SecondBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -462,14 +462,14 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/sp_midnight": { - if (bm.BattleNight is not INightInitial b) break; + if (bm.FirstBattle is not INightInitial b) break; SetFormation(bm); ClearAerialWarfare(); ClearSearchingResult(); ClearBaseAirAttack(); SetNightBattleEvent(b.NightInitial); - SetHPBar(bm.BattleNight); + SetHPBar(bm.SecondBattle); SetDamageRate(bm); // BaseLayoutPanel.Visible = !hideDuringBattle; @@ -480,13 +480,13 @@ private void Updated(string apiname, dynamic data) case "api_req_combined_battle/ec_night_to_day": { - var battle = bm.BattleNight as DayFromNightBattleData; + if (bm.FirstBattle is not DayFromNightBattleData battle) break; SetFormation(bm); ClearAerialWarfare(); ClearSearchingResult(); ClearBaseAirAttack(); - SetNightBattleEvent(battle!.NightInitial); + SetNightBattleEvent(battle.NightInitial); if (battle.NextToDay) { @@ -546,7 +546,7 @@ private void SetFormation(BattleManager bm) - if (bm.IsEnemyCombined && bm.StartsFromDayBattle) + if (bm.IsEnemyCombined) { // highlights for the fleet you'll fight in night battle // todo: this should probably go to config @@ -602,9 +602,9 @@ private void SetFormation(BattleManager bm) /// /// 索敵結果を設定します。 /// - private void SetSearchingResult(BattleData bd) + private void SetSearchingResult(FirstBattleData bd) { - if (bd is not FirstBattleData { Searching: { } searching }) return; + if (bd is not { Searching: { } searching }) return; DetectionType search = searching.PlayerDetectionType; @@ -1452,7 +1452,7 @@ private void SetMVPShip(BattleManager bm) { bool isCombined = bm.IsCombinedBattle; - BattleData bd = bm.BattleNight ?? bm.BattleDay; + BattleData bd = bm.SecondBattle ?? bm.FirstBattle; BattleResult br = bm.Result; IFleetData friend = bd.FleetsBeforeBattle.Fleet; diff --git a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs index 03fa748ab..7ca462943 100644 --- a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs +++ b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs @@ -154,7 +154,7 @@ private void Updated(string apiname, dynamic data) break; case "api_req_practice/battle": - _inSortie = [ KCDatabase.Instance.Battle.BattleDay.Initial.FriendFleetID ]; + _inSortie = [ KCDatabase.Instance.Battle.FirstBattle.Initial.FriendFleetID ]; break; } From 63bdee9cbc19ba1f6dd7fd7510d828949e68a589 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Wed, 31 Jul 2024 20:02:14 +0900 Subject: [PATCH 07/38] remove battle modes --- .../Data/Battle/BattleManager.cs | 53 +++++++------------ .../Data/TsunDbSubmission/EnemyComp.cs | 2 +- .../Sortie/Battle/BattleData.cs | 3 ++ 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 5f3df545d..4f761ded4 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -49,7 +49,6 @@ namespace ElectronicObserver.Data.Battle; /// public class BattleManager : APIWrapper { - public static string BattleLogPath => "BattleLog"; public delegate void ShipLevelUpHandler(IShipData ship, int nextLevel); @@ -91,50 +90,27 @@ public class BattleManager : APIWrapper // and heavy base air raid moved to BattleDay like regular BattleBaseAirRaid public List HeavyBaseAirRaids { get; } = []; - [Flags] - public enum BattleModes - { - Undefined, // 未定義 - Normal, // 昼夜戦(通常戦闘) - NightOnly, // 夜戦 - NightDay, // 夜昼戦 - AirBattle, // 航空戦 - AirRaid, // 長距離空襲戦 - Radar, // レーダー射撃 - Practice, // 演習 - BaseAirRaid, // 基地空襲戦 - BattlePhaseMask = 0xFF, // 戦闘形態マスク - CombinedTaskForce = 0x100, // 機動部隊 - CombinedSurface = 0x200, // 水上部隊 - CombinedMask = 0xFF00, // 連合艦隊仕様 - EnemyCombinedFleet = 0x10000, // 敵連合艦隊 - } - - /// - /// 戦闘種別 - /// - public BattleModes BattleMode { get; } - - /// /// 連合艦隊戦かどうか /// - public bool IsCombinedBattle => (BattleMode & BattleModes.CombinedMask) != 0; + public bool IsCombinedBattle => FirstBattle is { IsCombined: true }; /// /// 演習かどうか /// - public bool IsPractice => FirstBattle is BattlePracticeDay; + public bool IsPractice => FirstBattle is { IsPractice: true }; /// /// 敵が連合艦隊かどうか /// - public bool IsEnemyCombined => (BattleMode & BattleModes.EnemyCombinedFleet) != 0; + public bool IsEnemyCombined => FirstBattle is { IsEnemyCombined: true }; /// /// 基地空襲戦かどうか /// - public bool IsBaseAirRaid => (BattleMode & BattleModes.BattlePhaseMask) == BattleModes.BaseAirRaid; + public bool IsBaseAirRaid => FirstBattle is { IsBaseAirRaid: true }; + + public bool IsAirRaid => FirstBattle is { IsAirRaid: true }; /// /// 出撃中に入手した艦船数 @@ -731,15 +707,24 @@ void IncrementSpecialAttack(BattleData? bd) /// 敵の損害率を出力します。 public int PredictWinRank(out double friendrate, out double enemyrate) { - BattleData activeBattle = SecondBattle ?? FirstBattle; + BattleData? activeBattle = SecondBattle ?? FirstBattle; + + // should never happen + if (activeBattle is null) + { + friendrate = 0; + enemyrate = 0; + return -1; + } + BattleFleets fleetsBefore = activeBattle.FleetsBeforeBattle; List hpsBefore = activeBattle.InitialHPs.ToList(); List hpsAfter = activeBattle.ResultHPs.ToList(); - BattleRankPrediction prediction = (BattleMode & BattleModes.BattlePhaseMask) switch + BattleRankPrediction prediction = activeBattle switch { - BattleModes.AirRaid or BattleModes.Radar => new AirRaidBattleRankPrediction() + { IsAirRaid: true } or { IsRadar: true } => new AirRaidBattleRankPrediction() { FriendlyMainFleetBefore = fleetsBefore.Fleet, FriendlyMainFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.Fleet, hpsAfter, BattleSides.FriendMain)!, @@ -753,7 +738,7 @@ public int PredictWinRank(out double friendrate, out double enemyrate) EnemyEscortFleetBefore = fleetsBefore.EnemyEscortFleet, EnemyEscortFleetAfter = BattleRankPrediction.SimulateFleetAfterBattle(fleetsBefore.EnemyEscortFleet, hpsAfter, BattleSides.EnemyEscort), }, - BattleModes.BaseAirRaid => new BaseAirRaidBattleRankPrediction() + { IsBaseAirRaid: true } => new BaseAirRaidBattleRankPrediction() { AirBaseBeforeAfter = BaseAirRaidBattleRankPrediction.SimulateBaseAfterBattle(hpsBefore, hpsAfter), diff --git a/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs b/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs index f97fd4b54..76b3bd4cd 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/EnemyComp.cs @@ -93,6 +93,6 @@ public void PrepareEnemyCompFromCurrentState() EquipsEscort = initial.EnemySlotsEscort.Take(shipCount).ToList(); } - IsAirRaid = db.Battle.BattleMode == Data.Battle.BattleManager.BattleModes.AirRaid; + IsAirRaid = db.Battle.IsAirRaid; } } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index b2cb6744e..c10957d3f 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -20,7 +20,10 @@ public abstract class BattleData public bool IsPractice => this is BattlePracticeDay or BattlePracticeNight; public bool IsFriendCombined => FleetsBeforeBattle.EscortFleet is not null; public bool IsEnemyCombined => FleetsBeforeBattle.EnemyEscortFleet is not null; + public bool IsCombined => IsFriendCombined || IsEnemyCombined; public bool IsBaseAirRaid => this is BattleBaseAirRaid; + public bool IsRadar => this is BattleNormalRadar or BattleCombinedRadar; + public bool IsAirRaid => this is BattleAirRaid or BattleCombinedAirRaid; public IEnumerable InitialHPs => GetHpList(FleetsBeforeBattle.Fleet) .Concat(GetHpList(FleetsBeforeBattle.EscortFleet)) From d97f815018fd9ba402f846fcde15ad1e72d8dc30 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Wed, 31 Jul 2024 20:05:08 +0900 Subject: [PATCH 08/38] sonar --- ElectronicObserver/Data/Battle/BattleManager.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 4f761ded4..993874dd9 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -115,28 +115,28 @@ public class BattleManager : APIWrapper /// /// 出撃中に入手した艦船数 /// - public int DroppedShipCount { get; internal set; } + public int DroppedShipCount { get; private set; } /// /// 出撃中に入手した装備数 /// - public int DroppedEquipmentCount { get; internal set; } + public int DroppedEquipmentCount { get; private set; } /// /// 出撃中に入手したアイテム - ID と 個数 のペア /// - public Dictionary DroppedItemCount { get; } = []; + private Dictionary DroppedItemCount { get; } = []; /// /// 演習の敵提督名 /// - public string EnemyAdmiralName { get; internal set; } + private string? EnemyAdmiralName { get; set; } /// /// 演習の敵提督階級 /// - public string EnemyAdmiralRank { get; internal set; } + private string? EnemyAdmiralRank { get; set; } /// /// True if Resupply was used before the battle From f99eade76f626f64fac0296981f577ad1b7ff809 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Wed, 31 Jul 2024 20:11:38 +0900 Subject: [PATCH 09/38] sonar --- ElectronicObserver/Data/Battle/BattleManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 993874dd9..86a4f4d62 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -190,12 +190,9 @@ private BattleFleets Fleets } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] public override void LoadFromResponse(string apiname, dynamic data) { - IKCDatabase db = KCDatabase.Instance; - - //base.LoadFromResponse( apiname, data ); //不要 - object? apiData = DeserializeResponse(apiname, data.ToString()); HeavyBaseAirRaids.Clear(); From 9e25e1f85fa62797318d8fd7cfb0dd0a01d36713 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:30:28 +0900 Subject: [PATCH 10/38] add heavy base air raid response --- .../AirRaid/ApiReqMapAirRaidResponse.cs | 8 +++++ .../ApiReqMap/AirRaid/HeavyBaseAirRaidWave.cs | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/ApiReqMapAirRaidResponse.cs create mode 100644 ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/HeavyBaseAirRaidWave.cs diff --git a/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/ApiReqMapAirRaidResponse.cs b/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/ApiReqMapAirRaidResponse.cs new file mode 100644 index 000000000..61a778670 --- /dev/null +++ b/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/ApiReqMapAirRaidResponse.cs @@ -0,0 +1,8 @@ +namespace ElectronicObserver.KancolleApi.Types.ApiReqMap.AirRaid; + +// todo: no idea if there's supposed to be more data here +public class ApiReqMapAirRaidResponse +{ + [JsonPropertyName("api_destruction_battle")] + public List ApiDestructionBattle { get; set; } = []; +} diff --git a/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/HeavyBaseAirRaidWave.cs b/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/HeavyBaseAirRaidWave.cs new file mode 100644 index 000000000..d4b3cfdbb --- /dev/null +++ b/ElectronicObserver.KancolleApi.Types/ApiReqMap/AirRaid/HeavyBaseAirRaidWave.cs @@ -0,0 +1,36 @@ +using ElectronicObserver.KancolleApi.Types.ApiReqMap.Models; + +namespace ElectronicObserver.KancolleApi.Types.ApiReqMap.AirRaid; + +public class HeavyBaseAirRaidWave +{ + [JsonPropertyName("api_formation")] + public List ApiFormation { get; set; } = []; + + [JsonPropertyName("api_ship_ke")] + public List ApiShipKe { get; set; } = []; + + [JsonPropertyName("api_ship_lv")] + public List ApiShipLv { get; set; } = []; + + [JsonPropertyName("api_e_nowhps")] + public List ApiENowhps { get; set; } = []; + + [JsonPropertyName("api_e_maxhps")] + public List ApiEMaxhps { get; set; } = []; + + [JsonPropertyName("api_eSlot")] + public List> ApiESlot { get; set; } = []; + + [JsonPropertyName("api_f_nowhps")] + public List ApiFNowhps { get; set; } = []; + + [JsonPropertyName("api_f_maxhps")] + public List ApiFMaxhps { get; set; } = []; + + [JsonPropertyName("api_air_base_attack")] + public ApiAirBaseRaid ApiAirBaseAttack { get; set; } = null!; + + [JsonPropertyName("api_lost_kind")] + public int ApiLostKind { get; set; } +} From feba95bc9ace337759de0c1f6ea738048a311c6c Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:31:09 +0900 Subject: [PATCH 11/38] fix id dictionary null annotations --- ElectronicObserverTypes/Data/IDDictionary.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ElectronicObserverTypes/Data/IDDictionary.cs b/ElectronicObserverTypes/Data/IDDictionary.cs index 551842286..4208c95b1 100644 --- a/ElectronicObserverTypes/Data/IDDictionary.cs +++ b/ElectronicObserverTypes/Data/IDDictionary.cs @@ -8,7 +8,7 @@ namespace ElectronicObserverTypes.Data; /// IDを持つデータのリストを保持します。 /// /// -public class IDDictionary : IReadOnlyDictionary where TData : class?, IIdentifiable? +public class IDDictionary : IReadOnlyDictionary where TData : class, IIdentifiable { private readonly IDictionary dict; @@ -71,7 +71,7 @@ public bool TryGetValue(int key, out TData value) public IEnumerable Values => dict.Values; - public TData this[int key] => dict.ContainsKey(key) ? dict[key] : null; + public TData? this[int key] => dict.ContainsKey(key) ? dict[key] : null; public int Count => dict.Count; From 62bc195acbc46591a48a2ef0d7349d6a2411eef1 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:31:31 +0900 Subject: [PATCH 12/38] fix nullability --- ElectronicObserver/Data/KCDatabase.cs | 2 +- ElectronicObserver/Resource/Record/EnemyFleetRecord.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ElectronicObserver/Data/KCDatabase.cs b/ElectronicObserver/Data/KCDatabase.cs index 18318ef19..43771c8c2 100644 --- a/ElectronicObserver/Data/KCDatabase.cs +++ b/ElectronicObserver/Data/KCDatabase.cs @@ -58,7 +58,7 @@ public sealed class KCDatabase : IKCDatabase /// /// 保有装備のデータ /// - public IDDictionary Equipments { get; private set; } + public IDDictionary Equipments { get; private set; } /// diff --git a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs index 6314d1ad5..38bb1d7f3 100644 --- a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs +++ b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs @@ -169,7 +169,7 @@ private ulong ComputeHash() /// /// 現在の状態からインスタンスを生成します。 /// - public static EnemyFleetElement CreateFromCurrentState() + public static EnemyFleetElement? CreateFromCurrentState() { var battle = KCDatabase.Instance.Battle; From 8267fa20051ecc5c44c511380ddb30cd855a3e03 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:32:20 +0900 Subject: [PATCH 13/38] battle manager fixes --- .../Data/Battle/BattleManager.cs | 124 ++++++++++-------- .../Sortie/Battle/BattleFactory.cs | 12 ++ .../Sortie/Battle/Phase/PhaseInitial.cs | 2 + 3 files changed, 80 insertions(+), 58 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 86a4f4d62..9cdec45e8 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -34,12 +34,12 @@ using ElectronicObserver.KancolleApi.Types.Interfaces; using ElectronicObserver.Resource.Record; using ElectronicObserver.Utility.Mathematics; +using ElectronicObserver.Window.Dialog.BattleDetail; using ElectronicObserver.Window.Dialog.QuestTrackerManager.Enums; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; using ElectronicObserverTypes; -using ElectronicObserverTypes.Data; using ElectronicObserverTypes.Extensions; namespace ElectronicObserver.Data.Battle; @@ -51,13 +51,13 @@ public class BattleManager : APIWrapper { public static string BattleLogPath => "BattleLog"; - public delegate void ShipLevelUpHandler(IShipData ship, int nextLevel); - /// /// Ship will have the level before level up /// /// /// + public delegate void ShipLevelUpHandler(IShipData ship, int nextLevel); + public event ShipLevelUpHandler? ShipLevelUp; /// @@ -278,8 +278,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqSortieNightToDayResponse battle) break; - // todo - // BattleNight = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -321,8 +320,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleAirbattleResponse battle) break; - // todo - // BattleDay = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -364,8 +362,7 @@ public override void LoadFromResponse(string apiname, dynamic data) { if (apiData is not ApiReqCombinedBattleEcNightToDayResponse battle) break; - // todo - // BattleNight = BattleFactory.CreateBattle(battle, Fleets); + FirstBattle = BattleFactory.CreateBattle(battle, Fleets); } break; @@ -488,23 +485,27 @@ public override void LoadFromResponse(string apiname, dynamic data) /// private void BattleFinished() { - //敵編成記録 - EnemyFleetRecord.EnemyFleetElement enemyFleetData = EnemyFleetRecord.EnemyFleetElement.CreateFromCurrentState(); + EnemyFleetRecord.EnemyFleetElement? enemyFleetData = EnemyFleetRecord.EnemyFleetElement.CreateFromCurrentState(); if (enemyFleetData != null) + { RecordManager.Instance.EnemyFleet.Update(enemyFleetData); - + } // ロギング if (IsPractice) { + Debug.Assert(Result is not null); + Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedPractice, EnemyAdmiralName, EnemyAdmiralRank, Result.EnemyFleetName, Result.Rank, Result.AdmiralExp, Result.BaseExp)); } else if (IsBaseAirRaid) { + Debug.Assert(Compass is not null); + if (FirstBattle is BattleBaseAirRaid raid) { PhaseBaseAirRaid? airraid = raid.BaseAirRaid; @@ -533,6 +534,9 @@ private void BattleFinished() } else { + Debug.Assert(Compass is not null); + Debug.Assert(Result is not null); + Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedSortie, Compass.MapAreaID, Compass.MapInfoID, Compass.CellDisplay, KCDatabase.Instance.Translation.Operation.FleetName(Result.EnemyFleetName), Result.Rank, Result.AdmiralExp, Result.BaseExp)); @@ -542,6 +546,9 @@ private void BattleFinished() // Level up if (!IsBaseAirRaid) { + Debug.Assert(FirstBattle is not null); + Debug.Assert(Result is not null); + List exps = Result.ExpList; List> lvup = Result.LevelUpList; for (int i = 0; i < lvup.Count; i++) @@ -580,23 +587,24 @@ private void BattleFinished() //ドロップ艦記録 if (!IsPractice && !IsBaseAirRaid) { + Debug.Assert(Compass is not null); + Debug.Assert(Result is not null); + //checkme: とてもアレな感じ - int shipID = (int?)Result.DroppedShipId ?? -1; - int itemID = Result.DroppedItemId ?? -1; - int eqID = Result.DroppedEquipmentId ?? -1; + int shipId = (int?)Result.DroppedShipId ?? -1; + int itemId = Result.DroppedItemId ?? -1; + int eqId = Result.DroppedEquipmentId ?? -1; bool showLog = Utility.Configuration.Config.Log.ShowSpoiler; - if (shipID != -1) + if (KCDatabase.Instance.MasterShips[shipId] is IShipDataMaster ship) { - - IShipDataMaster ship = KCDatabase.Instance.MasterShips[(int)shipID]; DroppedShipCount++; IEnumerable? defaultSlot = ship.DefaultSlot?.Select(i => i switch { < 1 => null, - _ => KCDatabase.Instance.MasterEquipments[i] + _ => KCDatabase.Instance.MasterEquipments[i], }); if (defaultSlot != null) @@ -610,22 +618,21 @@ private void BattleFinished() Utility.Logger.Add(2, string.Format(LoggerRes.ShipAdded, ship.ShipTypeName, ship.NameWithClass)); } - if (itemID != -1) + if (itemId != -1) { - DroppedItemCount.TryAdd(itemID, 0); - DroppedItemCount[itemID]++; + DroppedItemCount.TryAdd(itemId, 0); + DroppedItemCount[itemId]++; if (showLog) { - IUseItem? item = KCDatabase.Instance.UseItems[itemID]; - IUseItemMaster? itemmaster = KCDatabase.Instance.MasterUseItems[itemID]; - Utility.Logger.Add(2, string.Format(LoggerRes.ItemObtained, itemmaster?.NameTranslated ?? (BattleRes.UnknownItem + itemID), (item?.Count ?? 0) + DroppedItemCount[itemID])); + IUseItem? item = KCDatabase.Instance.UseItems[itemId]; + IUseItemMaster? itemMaster = KCDatabase.Instance.MasterUseItems[itemId]; + Utility.Logger.Add(2, string.Format(LoggerRes.ItemObtained, itemMaster?.NameTranslated ?? (BattleRes.UnknownItem + itemId), (item?.Count ?? 0) + DroppedItemCount[itemId])); } } - if (eqID != -1) + if (KCDatabase.Instance.MasterEquipments[eqId] is IEquipmentDataMaster eq) { - IEquipmentDataMaster eq = KCDatabase.Instance.MasterEquipments[eqID]; if (eq.UsesSlotSpace()) { DroppedEquipmentCount++; @@ -639,14 +646,16 @@ private void BattleFinished() // 満員判定 - if (shipID == -1 && ( + if (shipId == -1 && ( KCDatabase.Instance.Admiral.MaxShipCount - (KCDatabase.Instance.Ships.Count + DroppedShipCount) <= 0 || KCDatabase.Instance.Admiral.MaxEquipmentCount - (KCDatabase.Instance.Equipments.Values.Count(e => e.MasterEquipment.UsesSlotSpace()) + DroppedEquipmentCount) <= 0)) { - shipID = -2; + shipId = -2; } - RecordManager.Instance.ShipDrop.Add(shipID, itemID, eqID, Compass.MapAreaID, Compass.MapInfoID, Compass.CellId, Compass.MapInfo.EventDifficulty, Compass.EventID == 5, enemyFleetData.FleetID, Result.Rank, KCDatabase.Instance.Admiral.Level); + Debug.Assert(enemyFleetData is not null); + + RecordManager.Instance.ShipDrop.Add(shipId, itemId, eqId, Compass.MapAreaID, Compass.MapInfoID, Compass.CellId, Compass.MapInfo.EventDifficulty, Compass.EventID == 5, enemyFleetData.FleetID, Result.Rank, KCDatabase.Instance.Admiral.Level); } @@ -700,17 +709,17 @@ void IncrementSpecialAttack(BattleData? bd) /// /// 勝利ランクを予測します。 /// - /// 味方の損害率を出力します。 - /// 敵の損害率を出力します。 - public int PredictWinRank(out double friendrate, out double enemyrate) + /// 味方の損害率を出力します。 + /// 敵の損害率を出力します。 + public int PredictWinRank(out double friendRate, out double enemyRate) { BattleData? activeBattle = SecondBattle ?? FirstBattle; // should never happen if (activeBattle is null) { - friendrate = 0; - enemyrate = 0; + friendRate = 0; + enemyRate = 0; return -1; } @@ -719,6 +728,8 @@ public int PredictWinRank(out double friendrate, out double enemyrate) List hpsBefore = activeBattle.InitialHPs.ToList(); List hpsAfter = activeBattle.ResultHPs.ToList(); + Debug.Assert(fleetsBefore.EnemyFleet is not null); + BattleRankPrediction prediction = activeBattle switch { { IsAirRaid: true } or { IsRadar: true } => new AirRaidBattleRankPrediction() @@ -763,8 +774,8 @@ public int PredictWinRank(out double friendrate, out double enemyrate) BattleRank rank = prediction.PredictRank(); - friendrate = prediction.FriendHpRate; - enemyrate = prediction.EnemyHpRate; + friendRate = prediction.FriendHpRate; + enemyRate = prediction.EnemyHpRate; return (int)rank; } @@ -775,15 +786,17 @@ public int PredictWinRank(out double friendrate, out double enemyrate) public bool WillNightBattleWithMainFleet() { if (!IsEnemyCombined) return false; // ? true? + if (FirstBattle?.Initial is not { IsEnemyCombined: true } initial) return false; // ? true? - var initial = FirstBattle.Initial; int score = 0; + List resultHps = FirstBattle.ResultHPs.ToList(); + for (int i = 0; i < initial.EnemyInitialHPsEscort.Count; i++) { - if (initial.EnemyMembersEscort.ToList()[i] > 0) + if (initial.EnemyMembersEscort[i] > 0) { - double rate = (double)FirstBattle.ResultHPs.ToList()[BattleIndex.Get(BattleSides.EnemyEscort, i)] / - initial.EnemyMaxHPsEscort.ToList()[i]; + double rate = (double)resultHps[BattleIndex.Get(BattleSides.EnemyEscort, i)] / + initial.EnemyMaxHPsEscort[i]; if (rate > 0.5) { @@ -807,36 +820,31 @@ public bool WillNightBattleWithMainFleet() private void WriteBattleLog() { - - if (!Utility.Configuration.Config.Log.SaveBattleLog) - return; + if (!Utility.Configuration.Config.Log.SaveBattleLog) return; try { string parent = BattleLogPath; - if (!Directory.Exists(parent)) - Directory.CreateDirectory(parent); + Directory.CreateDirectory(parent); + + string info = (IsPractice, Compass) switch + { + (true, _) => "practice", + (_, not null) => $"{Compass.MapAreaID}-{Compass.MapInfoID}-{Compass.CellId}", - string info; - if (IsPractice) - info = "practice"; - else - info = $"{Compass.MapAreaID}-{Compass.MapInfoID}-{Compass.CellId}"; + // should never happen + _ => "???", + }; string path = $"{parent}\\{DateTimeHelper.GetTimeStamp()}@{info}.txt"; - using (var sw = new StreamWriter(path, false, Utility.Configuration.Config.Log.FileEncoding)) - { - // todo sw.Write(BattleDetailDescriptor.GetBattleDetail(this)); - } - + using StreamWriter sw = new(path, false, Utility.Configuration.Config.Log.FileEncoding); + sw.Write(BattleDetailDescriptor.GetBattleDetail(this)); } catch (Exception ex) { - Utility.ErrorReporter.SendErrorReport(ex, "戦闘ログの出力に失敗しました。"); } } - } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs index 47be82cfb..e607d552b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleFactory.cs @@ -1,11 +1,13 @@ using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqBattleMidnight.SpMidnight; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Airbattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.BattleWater; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EachBattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EachBattleWater; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcBattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcMidnightBattle; +using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.EcNightToDay; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdAirbattle; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.LdShooting; using ElectronicObserver.KancolleApi.Types.ApiReqCombinedBattle.MidnightBattle; @@ -17,6 +19,7 @@ using ElectronicObserver.KancolleApi.Types.ApiReqSortie.Battle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdAirbattle; using ElectronicObserver.KancolleApi.Types.ApiReqSortie.LdShooting; +using ElectronicObserver.KancolleApi.Types.ApiReqSortie.NightToDay; using ElectronicObserver.KancolleApi.Types.Legacy.OpeningTorpedoRework; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; @@ -95,6 +98,15 @@ public BattleCombinedEachDay CreateBattle(OpeningTorpedoRework_ApiReqCombinedBat public BattleCombinedEachWater CreateBattle(OpeningTorpedoRework_ApiReqCombinedBattleEachBattleWaterResponse battle, BattleFleets fleets) => new(PhaseFactory, fleets, battle); + public BattleNormalDayFromNight CreateBattle(ApiReqSortieNightToDayResponse battle, BattleFleets fleets) + => new(PhaseFactory, fleets, battle); + + public BattleEnemyCombinedDayFromNight CreateBattle(ApiReqCombinedBattleEcNightToDayResponse battle, BattleFleets fleets) + => new(PhaseFactory, fleets, battle); + + public BattleCombinedAirBattle CreateBattle(ApiReqCombinedBattleAirbattleResponse battle, BattleFleets fleets) + => new(PhaseFactory, fleets, battle); + public BattlePracticeDay CreateBattle(ApiReqPracticeBattleResponse battle, BattleFleets fleets) => new(PhaseFactory, fleets, battle); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index 2f039f8e6..9941d907c 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -49,7 +49,9 @@ public class PhaseInitial : PhaseBase public IEquipmentData?[][] EnemySlotsInstance => EnemyMembersInstance.Select(s => s?.SlotInstance.ToArray() ?? []).ToArray(); [MemberNotNullWhen(true, nameof(EnemyMembersEscort))] + [MemberNotNullWhen(true, nameof(EnemyMembersEscortInstance))] [MemberNotNullWhen(true, nameof(EnemyLevelsEscort))] + [MemberNotNullWhen(true, nameof(EnemyInitialHPsEscort))] [MemberNotNullWhen(true, nameof(EnemyMaxHPsEscort))] [MemberNotNullWhen(true, nameof(EnemyParametersEscort))] [MemberNotNullWhen(true, nameof(EnemySlotsEscort))] From a24bac78adcf77dfbcf2260bb9c3e09707aacbe7 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:36:14 +0900 Subject: [PATCH 14/38] update battle deserialization --- ElectronicObserver/Data/Battle/BattleManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index 9cdec45e8..bb32089b0 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -454,15 +454,15 @@ public override void LoadFromResponse(string apiname, dynamic data) "api_req_battle_midnight/sp_midnight" => JsonSerializer.Deserialize(json), "api_req_sortie/airbattle" => JsonSerializer.Deserialize(json), "api_req_sortie/ld_airbattle" => JsonSerializer.Deserialize(json), - "api_req_sortie/night_to_day" => throw new NotImplementedException(), + "api_req_sortie/night_to_day" => JsonSerializer.Deserialize(json), "api_req_sortie/ld_shooting" => JsonSerializer.Deserialize(json), "api_req_combined_battle/battle" => JsonSerializer.Deserialize(json), "api_req_combined_battle/sp_midnight" => JsonSerializer.Deserialize(json), - "api_req_combined_battle/airbattle" => throw new NotImplementedException(), + "api_req_combined_battle/airbattle" => JsonSerializer.Deserialize(json), "api_req_combined_battle/battle_water" => JsonSerializer.Deserialize(json), "api_req_combined_battle/ld_airbattle" => JsonSerializer.Deserialize(json), "api_req_combined_battle/ec_battle" => JsonSerializer.Deserialize(json), - "api_req_combined_battle/ec_night_to_day" => throw new NotImplementedException(), + "api_req_combined_battle/ec_night_to_day" => JsonSerializer.Deserialize(json), "api_req_combined_battle/each_battle" => JsonSerializer.Deserialize(json), "api_req_combined_battle/each_battle_water" => JsonSerializer.Deserialize(json), "api_req_combined_battle/ld_shooting" => JsonSerializer.Deserialize(json), From 79b46190f52b42a5140198358b296a5cc24343a2 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 18:42:47 +0900 Subject: [PATCH 15/38] sonar --- .../Data/Battle/BattleManager.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ElectronicObserver/Data/Battle/BattleManager.cs b/ElectronicObserver/Data/Battle/BattleManager.cs index bb32089b0..10ce76309 100644 --- a/ElectronicObserver/Data/Battle/BattleManager.cs +++ b/ElectronicObserver/Data/Battle/BattleManager.cs @@ -40,6 +40,7 @@ using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; using ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Node; using ElectronicObserverTypes; +using ElectronicObserverTypes.Attacks; using ElectronicObserverTypes.Extensions; namespace ElectronicObserver.Data.Battle; @@ -510,7 +511,7 @@ private void BattleFinished() { PhaseBaseAirRaid? airraid = raid.BaseAirRaid; List initialHPs = FirstBattle.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); - int damage = initialHPs.Zip(FirstBattle.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); + int damage = initialHPs.Zip(FirstBattle.ResultHPs.Take(initialHPs.Count), (initial, result) => initial - result).Sum(); Utility.Logger.Add(2, string.Format(BattleRes.BattleFinishedBaseAirRaid, @@ -521,7 +522,7 @@ private void BattleFinished() foreach (BattleBaseAirRaid battleBaseAirRaid in HeavyBaseAirRaids) { List initialHPs = battleBaseAirRaid.Initial.FriendInitialHPs.TakeWhile(hp => hp >= 0).ToList(); - int damage = initialHPs.Zip(battleBaseAirRaid.ResultHPs.Take(initialHPs.Count()), (initial, result) => initial - result).Sum(); + int damage = initialHPs.Zip(battleBaseAirRaid.ResultHPs.Take(initialHPs.Count), (initial, result) => initial - result).Sum(); PhaseBaseAirRaid? baseAirRaid = battleBaseAirRaid.BaseAirRaid; int airRaidDamageKind = baseAirRaid?.ApiLostKind ?? 0; @@ -669,13 +670,14 @@ void IncrementSpecialAttack(BattleData? bd) { case PhaseShelling shelling: { - foreach (PhaseShellingAttackViewModel attack in shelling.AttackDisplays + foreach (DayAttackKind attackType in shelling.AttackDisplays .Where(a => a.AttackerIndex.FleetFlag is FleetFlag.Player) - .Where(a => TracedSpecialAttack.Contains((int)a.AttackType))) + .Select(a => a.AttackType) + .Where(a => TracedSpecialAttack.Contains((int)a))) { - if (!SpecialAttackCount.TryAdd((int)attack.AttackType, 1)) + if (!SpecialAttackCount.TryAdd((int)attackType, 1)) { - SpecialAttackCount[(int)attack.AttackType]++; + SpecialAttackCount[(int)attackType]++; } } @@ -684,13 +686,14 @@ void IncrementSpecialAttack(BattleData? bd) case PhaseNightBattle night: { - foreach (PhaseNightBattleAttackViewModel attack in night.AttackDisplays + foreach (NightAttackKind attackType in night.AttackDisplays .Where(a => a.AttackerIndex.FleetFlag is FleetFlag.Player) - .Where(a => TracedSpecialAttack.Contains((int)a.AttackType))) + .Select(a => a.AttackType) + .Where(a => TracedSpecialAttack.Contains((int)a))) { - if (!SpecialAttackCount.TryAdd((int)attack.AttackType, 1)) + if (!SpecialAttackCount.TryAdd((int)attackType, 1)) { - SpecialAttackCount[(int)attack.AttackType]++; + SpecialAttackCount[(int)attackType]++; } } From 4d601d3cb8db9dcd3cd515372042d24406d63ced Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 19:25:12 +0900 Subject: [PATCH 16/38] sonar --- .../Resource/Record/ShipParameterRecord.cs | 4 +- .../BattleDetail/BattleDetailDescriptor.cs | 73 +++++++++++++------ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/ElectronicObserver/Resource/Record/ShipParameterRecord.cs b/ElectronicObserver/Resource/Record/ShipParameterRecord.cs index 63e452de2..88b6dc01d 100644 --- a/ElectronicObserver/Resource/Record/ShipParameterRecord.cs +++ b/ElectronicObserver/Resource/Record/ShipParameterRecord.cs @@ -275,12 +275,12 @@ public sealed class ShipParameterElement : RecordElementBase /// /// 初期装備 /// - public int[] DefaultSlot { get; internal set; } + public int[]? DefaultSlot { get; internal set; } /// /// 搭載機数 /// - public int[] Aircraft { get; internal set; } + public int[]? Aircraft { get; internal set; } /// diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs index 8f2d9d237..8fdcd75d4 100644 --- a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using ElectronicObserver.Data; @@ -28,6 +29,8 @@ public static string GetBattleDetail(BattleManager bm) } else { + Debug.Assert(bm.Compass is not null); + sb.AppendFormat("{0} ({1}-{2})", bm.Compass.MapInfo.NameEN, bm.Compass.MapAreaID, bm.Compass.MapInfoID); if (bm.Compass.MapInfo.EventDifficulty > 0) sb.AppendFormat(" [{0}]", Constants.GetDifficulty(bm.Compass.MapInfo.EventDifficulty)); @@ -69,6 +72,8 @@ public static string GetBattleDetail(BattleManager bm) } else { + Debug.Assert(bm.FirstBattle is not null); + sb.AppendFormat("◆ {0} ◆\r\n", bm.FirstBattle.Title).AppendLine(GetBattleDetail(bm.FirstBattle)); if (bm.SecondBattle != null) sb.AppendFormat("◆ {0} ◆\r\n", bm.SecondBattle.Title).AppendLine(GetBattleDetail(bm.SecondBattle)); @@ -161,7 +166,7 @@ public static string GetBattleDetail(BattleData battle) void AppendFleetInfo(IFleetData fleet) { sb.Append($" {BattleRes.AirSuperiority} "); - sb.Append(GetRangeString(Calculator.GetAirSuperiority(fleet, false), + sb.Append(GetRangeString(Calculator.GetAirSuperiority(fleet), Calculator.GetAirSuperiority(fleet, true))); static double Truncate2(double value) => Math.Floor(value * 100) / 100; @@ -261,6 +266,8 @@ void AppendEnemyFleetInfo(int[] members) if (battle.Phases.Any(ph => ph is PhaseBaseAirAttack or PhaseBaseAirRaid)) { + Debug.Assert(KCDatabase.Instance.Battle.Compass is not null); + sb.AppendLine(ConstantsRes.BattleDetail_AirBase); GetBattleDetailBaseAirCorps(sb, KCDatabase.Instance.Battle.Compass.MapAreaID); // :( sb.AppendLine(); @@ -414,7 +421,7 @@ void AppendEnemyFleetInfo(int[] members) { sbmaster.AppendLine(ConstantsRes.BattleDetail_BattleEnd); - IFleetData? friend = battle.FleetsAfterBattle.Fleet; + IFleetData friend = battle.FleetsAfterBattle.Fleet; IFleetData? friendescort = battle.FleetsAfterBattle.EscortFleet; List enemy = battle.Initial.EnemyMembersInstance; List? enemyescort = battle.Initial.EnemyMembersEscortInstance; @@ -440,11 +447,11 @@ void AppendEnemyFleetInfo(int[] members) } else { - for (int i = 0; i < friend.Members.Count(); i++) + Debug.Assert(friend.Members is not null); + + for (int i = 0; i < friend.Members.Count; i++) { - var ship = friend.MembersInstance[i]; - if (ship == null) - continue; + if (friend.MembersInstance[i] is not IShipData ship) continue; OutputResultData(sbmaster, i, ship.Name, battle.Initial.FriendInitialHPs[i], resultHps[i], battle.Initial.FriendMaxHPs[i]); @@ -453,9 +460,13 @@ void AppendEnemyFleetInfo(int[] members) if (friendescort != null) { + Debug.Assert(friendescort.Members is not null); + Debug.Assert(battle.Initial.FriendInitialHPsEscort is not null); + Debug.Assert(battle.Initial.FriendMaxHPsEscort is not null); + sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_FriendEscortFleet); - for (int i = 0; i < friendescort.Members.Count(); i++) + for (int i = 0; i < friendescort.Members.Count; i++) { var ship = friendescort.MembersInstance[i]; if (ship == null) @@ -487,13 +498,14 @@ void AppendEnemyFleetInfo(int[] members) if (enemyescort != null) { + Debug.Assert(battle.Initial.EnemyInitialHPsEscort is not null); + Debug.Assert(battle.Initial.EnemyMaxHPsEscort is not null); + sbmaster.AppendLine().AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); for (int i = 0; i < enemyescort.Count; i++) { - IShipData? ship = enemyescort[i]; - if (ship == null) - continue; + if (enemyescort[i] is not IShipData ship) continue; OutputResultData(sbmaster, i + 6, ship.MasterShip.NameWithClass, battle.Initial.EnemyInitialHPsEscort[i], resultHps[i + 18], battle.Initial.EnemyMaxHPsEscort[i]); @@ -514,10 +526,12 @@ private static void GetBattleDetailBaseAirCorps(StringBuilder sb, int mapAreaID) { sb.AppendFormat("{0} [{1}] " + BattleRes.AirSuperiority + " {2}\r\n {3}\r\n", corps.Name, Constants.GetBaseAirCorpsActionKind(corps.ActionKind), - GetRangeString(Calculator.GetAirSuperiority(corps, false), Calculator.GetAirSuperiority(corps, true)), + GetRangeString(Calculator.GetAirSuperiority(corps), Calculator.GetAirSuperiority(corps, true)), string.Join(", ", corps.Squadrons.Values - .Where(sq => sq.State == 1 && sq.EquipmentInstance != null) - .Select(sq => sq.EquipmentInstance.NameWithLevel))); + .Where(sq => sq.State == 1) + .Select(sq => sq.EquipmentInstance) + .OfType() + .Select(eq => eq.NameWithLevel))); } } @@ -664,6 +678,7 @@ private static void OutputSupportData(StringBuilder sb, IFleetData fleet) private static void OutputFriendlySupportData(StringBuilder sb, PhaseFriendlySupportInfo p) { + Debug.Assert(p.FleetsBeforePhase?.FriendFleet is not null); for (int i = 0; i < p.FleetsBeforePhase.FriendFleet.MembersInstance.Count; i++) { @@ -697,13 +712,12 @@ private static void OutputEnemyData(StringBuilder sb, List members, for (int i = 0; i < members.Count; i++) { - if (members[i] == null) - continue; + if (members[i] is not IShipData ship) continue; sb.AppendFormat("#{0}: ID:{1} {2} {3} Lv. {4} HP: {5} / {6}", i + 1, - members[i].ShipID, - members[i].MasterShip.ShipTypeName, members[i].MasterShip.NameWithClass, + ship.ShipID, + ship.MasterShip.ShipTypeName, ship.MasterShip.NameWithClass, levels[i], initialHPs[i], maxHPs[i]); @@ -736,6 +750,9 @@ private static void OutputResultData(StringBuilder sb, int index, string name, i private static string GetBattleResult(BattleManager bm) { + Debug.Assert(bm.Result is not null); + Debug.Assert(bm.FirstBattle is not null); + BattleResult result = bm.Result; StringBuilder sb = new(); @@ -746,15 +763,25 @@ private static string GetBattleResult(BattleManager bm) if (bm.IsCombinedBattle) { - sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPMain + "\r\n", - result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex].NameWithLevel); - sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPEscort + "\r\n", - result.MvpIndexCombined == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.EscortFleet.MembersInstance[result.MvpIndexCombined.Value].NameWithLevel); + sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPMain + "\r\n", result.MvpIndex switch + { + -1 => "(なし)", + _ => bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex]?.NameWithLevel, + }); + + sb.AppendFormat(ConstantsRes.BattleDetail_ResultMVPEscort + "\r\n", result.MvpIndexCombined switch + { + -1 or null => "(なし)", + int index => bm.FirstBattle.FleetsBeforeBattle.EscortFleet!.MembersInstance[index]?.NameWithLevel, + }); } else { - sb.AppendFormat("MVP: {0}\r\n", - result.MvpIndex == -1 ? "(なし)" : bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex].NameWithLevel); + sb.AppendFormat("MVP: {0}\r\n", result.MvpIndex switch + { + -1 => "(なし)", + _ => bm.FirstBattle.FleetsBeforeBattle.Fleet.MembersInstance[result.MvpIndex]?.NameWithLevel, + }); } sb.AppendFormat(ConstantsRes.BattleDetail_AdmiralExp + "\r\n", result.AdmiralExp); From 822fde2ded2cc0f2966e9faddb93c2c43bfc7053 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 19:38:25 +0900 Subject: [PATCH 17/38] sonar --- .../BattleDetail/BattleDetailDescriptor.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs index 8fdcd75d4..68555b1a2 100644 --- a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -18,6 +18,7 @@ namespace ElectronicObserver.Window.Dialog.BattleDetail; public static class BattleDetailDescriptor { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] public static string GetBattleDetail(BattleManager bm) { StringBuilder sb = new(); @@ -34,7 +35,7 @@ public static string GetBattleDetail(BattleManager bm) sb.AppendFormat("{0} ({1}-{2})", bm.Compass.MapInfo.NameEN, bm.Compass.MapAreaID, bm.Compass.MapInfoID); if (bm.Compass.MapInfo.EventDifficulty > 0) sb.AppendFormat(" [{0}]", Constants.GetDifficulty(bm.Compass.MapInfo.EventDifficulty)); - sb.Append(ConstantsRes.BattleDetail_Node).Append(bm.Compass.CellId.ToString()); + sb.Append(ConstantsRes.BattleDetail_Node).Append(bm.Compass.CellId); if (bm.Compass.EventID == 5) sb.Append(ConstantsRes.BattleDetail_Boss); sb.AppendLine(); @@ -88,7 +89,7 @@ public static string GetBattleDetail(BattleManager bm) return sb.ToString(); } - + [System.Diagnostics.CodeAnalysis.SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] public static string GetBattleDetail(BattleData battle) { StringBuilder sbmaster = new(); @@ -103,7 +104,7 @@ public static string GetBattleDetail(BattleData battle) case PhaseBaseAirRaid p: sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", + sb.Append(' ').AppendLine(string.Join(", ", p.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()) .DefaultIfEmpty(BattleRes.Empty))); @@ -124,7 +125,7 @@ public static string GetBattleDetail(BattleData battle) sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.WaveIndex + 1); sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", + sb.Append(' ').AppendLine(string.Join(", ", a.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()))); GetBattleDetailPhaseAirBattle(sb, a); @@ -145,7 +146,7 @@ public static string GetBattleDetail(BattleData battle) sb.AppendFormat(ConstantsRes.BattleDetail_AirAttackWave + "\r\n", a.WaveIndex + 1); sb.AppendLine(ConstantsRes.BattleDetail_AirAttackUnits); - sb.Append(" ").AppendLine(string.Join(", ", + sb.Append(' ').AppendLine(string.Join(", ", a.Squadrons.Where(sq => sq.Equipment != null).Select(sq => sq.ToString()))); GetBattleDetailPhaseAirBattle(sb, a); @@ -569,7 +570,6 @@ private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseAirBatt sb.AppendLine(); } - private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseBaseAirRaid p) { @@ -604,7 +604,6 @@ private static void GetBattleDetailPhaseAirBattle(StringBuilder sb, PhaseBaseAir sb.AppendLine(); } - private static void OutputFriendData(StringBuilder sb, IFleetData fleet, List initialHPs, List maxHPs) { @@ -627,7 +626,7 @@ private static void OutputFriendData(StringBuilder sb, IFleetData fleet, List 0 ? ship.Aircraft.Concat(new[] { 0 }) : ship.Aircraft, (eq, aircraft) => eq == null ? null : ((eq.MasterEquipment.IsAircraft ? $"[{aircraft}] " : "") + eq.NameWithLevel) @@ -670,7 +669,7 @@ private static void OutputSupportData(StringBuilder sb, IFleetData fleet) ship.MasterShip.ShipTypeName, ship.NameWithLevel, ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase); - sb.Append(" "); + sb.Append(' '); sb.AppendLine(string.Join(", ", ship.AllSlotInstance.Where(eq => eq != null))); } @@ -700,7 +699,7 @@ private static void OutputFriendlySupportData(StringBuilder sb, PhaseFriendlySup ship.HPCurrent, ship.HPMax, ship.FirepowerBase, ship.TorpedoBase, ship.AABase, ship.ArmorBase); - sb.Append(" "); + sb.Append(' '); sb.AppendLine(string.Join(", ", ship.AllSlotInstance .OfType() .Select(eq => eq.MasterEquipment.NameEN))); @@ -731,12 +730,11 @@ private static void OutputEnemyData(StringBuilder sb, List members, parameters[i][0], parameters[i][1], parameters[i][2], parameters[i][3]); } - sb.AppendLine().Append(" "); + sb.AppendLine().Append(' '); sb.AppendLine(string.Join(", ", slots[i].Where(eq => eq != null))); } } - private static void OutputResultData(StringBuilder sb, int index, string name, int initialHP, int resultHP, int maxHP) { sb.AppendFormat("#{0}: {1} HP: ({2} → {3})/{4} ({5})\r\n", @@ -747,7 +745,7 @@ private static void OutputResultData(StringBuilder sb, int index, string name, i resultHP - initialHP); } - + [System.Diagnostics.CodeAnalysis.SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] private static string GetBattleResult(BattleManager bm) { Debug.Assert(bm.Result is not null); @@ -809,7 +807,7 @@ private static string GetBattleResult(BattleManager bm) IUseItemMaster? item = KCDatabase.Instance.MasterUseItems[result.DroppedItemId ?? -1]; if (item != null) { - sb.Append(" ").AppendLine(item.NameTranslated); + sb.Append(' ').AppendLine(item.NameTranslated); } if (length == sb.Length) @@ -821,6 +819,4 @@ private static string GetBattleResult(BattleManager bm) return sb.ToString(); } - } - From ad9467bfd68e0133e68a7e3742639a2d7d04a64a Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 19:52:59 +0900 Subject: [PATCH 18/38] sonar --- .../Window/Dialog/BattleDetail/BattleDetailDescriptor.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs index 68555b1a2..ef11a8b9f 100644 --- a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -156,7 +156,7 @@ public static string GetBattleDetail(BattleData battle) break; case PhaseInitial p: - + Debug.Assert(p.FleetsBeforePhase is not null); if (p.FleetsBeforePhase.EscortFleet != null) sb.Append(ConstantsRes.BattleDetail_FriendMainFleet); @@ -192,6 +192,9 @@ void AppendFleetInfo(IFleetData fleet) if (p.FleetsBeforePhase.EscortFleet != null) { + Debug.Assert(p.FriendInitialHPsEscort is not null); + Debug.Assert(p.FriendMaxHPsEscort is not null); + sb.AppendLine(); sb.Append(ConstantsRes.BattleDetail_FriendEscortFleet); AppendFleetInfo(p.FleetsBeforePhase.EscortFleet); @@ -251,7 +254,7 @@ void AppendEnemyFleetInfo(int[] members) p.EnemySlotsInstance, p.EnemyParameters); - if (p.EnemyMembersEscort != null) + if (p.IsEnemyCombined) { sb.AppendLine(); sb.AppendLine(ConstantsRes.BattleDetail_EnemyEscortFleet); @@ -387,7 +390,7 @@ void AppendEnemyFleetInfo(int[] members) if (p.FlareFriend is not null) { sb.AppendFormat(ConstantsRes.BattleDetail_FriendlyStarshell + "\r\n", - p.FlareEnemy.MasterShip.NameWithClass, p.FlareIndexFriend + 1); + p.FlareFriend.MasterShip.NameWithClass, p.FlareIndexFriend + 1); } if (p.FlareEnemy is not null) From 50870f2d5ffa51b1694a09bd28f23e1579522905 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:07:21 +0900 Subject: [PATCH 19/38] sonar --- .../Window/Dialog/BattleDetail/BattleDetailDescriptor.cs | 2 +- .../SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs index ef11a8b9f..e6efe0f3b 100644 --- a/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs +++ b/ElectronicObserver/Window/Dialog/BattleDetail/BattleDetailDescriptor.cs @@ -631,7 +631,7 @@ private static void OutputFriendData(StringBuilder sb, IFleetData fleet, List 0 ? ship.Aircraft.Concat(new[] { 0 }) : ship.Aircraft, + ship.ExpansionSlot > 0 ? ship.Aircraft.Concat([0]) : ship.Aircraft, (eq, aircraft) => eq == null ? null : ((eq.MasterEquipment.IsAircraft ? $"[{aircraft}] " : "") + eq.NameWithLevel) ).Where(str => str != null))); } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index 9941d907c..a0cedb275 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -55,6 +55,7 @@ public class PhaseInitial : PhaseBase [MemberNotNullWhen(true, nameof(EnemyMaxHPsEscort))] [MemberNotNullWhen(true, nameof(EnemyParametersEscort))] [MemberNotNullWhen(true, nameof(EnemySlotsEscort))] + [MemberNotNullWhen(true, nameof(EnemySlotsInstance))] public bool IsEnemyCombined => EnemyMembersEscortInstance is not null; public int[]? EnemyMembersEscort => EnemyMembersEscortInstance?.Select(s => s?.MasterShip.ShipID ?? -1).ToArray(); From 052da950db7e086d7e12ef274a68bf1def6b3716 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:14:02 +0900 Subject: [PATCH 20/38] fix --- .../SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index a0cedb275..a755edca3 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -55,7 +55,7 @@ public class PhaseInitial : PhaseBase [MemberNotNullWhen(true, nameof(EnemyMaxHPsEscort))] [MemberNotNullWhen(true, nameof(EnemyParametersEscort))] [MemberNotNullWhen(true, nameof(EnemySlotsEscort))] - [MemberNotNullWhen(true, nameof(EnemySlotsInstance))] + [MemberNotNullWhen(true, nameof(EnemySlotsEscortInstance))] public bool IsEnemyCombined => EnemyMembersEscortInstance is not null; public int[]? EnemyMembersEscort => EnemyMembersEscortInstance?.Select(s => s?.MasterShip.ShipID ?? -1).ToArray(); From c121d899c91c3ce36fd148f8875505c46eb472a0 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:20:31 +0900 Subject: [PATCH 21/38] update R# config --- ElectronicObserver.sln.DotSettings | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ElectronicObserver.sln.DotSettings b/ElectronicObserver.sln.DotSettings index 487ded1e6..52e0e3493 100644 --- a/ElectronicObserver.sln.DotSettings +++ b/ElectronicObserver.sln.DotSettings @@ -1,2 +1,3 @@  - HINT \ No newline at end of file + HINT + HINT \ No newline at end of file From e904a9622fb793f96fbb0636fa2e6dc48f8befb7 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:20:47 +0900 Subject: [PATCH 22/38] sonar --- .../Sortie/Battle/Phase/PhaseAirBattleBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs index 2e32083d7..6d6474f52 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseAirBattleBase.cs @@ -112,7 +112,7 @@ public class PhaseAirBattleBase : AttackPhaseBase, IPhaseAirBattle public string? TouchAircraftFriend => Stage1?.ApiTouchPlane switch { - [EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, + [EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id]?.NameEN, _ => null, }; public string? TouchAircraftFriendDisplay => TouchAircraftFriend switch @@ -123,7 +123,7 @@ public class PhaseAirBattleBase : AttackPhaseBase, IPhaseAirBattle public string? TouchAircraftEnemy => Stage1?.ApiTouchPlane switch { - [_, EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id].NameEN, + [_, EquipmentId id and > 0, ..] => KcDatabase.MasterEquipments[(int)id]?.NameEN, _ => null, }; public string? TouchAircraftEnemyDisplay => TouchAircraftEnemy switch From 04d98fcc5f1a181ef3b23f3f0eda1e1fe58153c7 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:27:53 +0900 Subject: [PATCH 23/38] sonar --- .../Sortie/Battle/Phase/PhaseBaseAirRaid.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs index 0205964d5..53c584fbb 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseBaseAirRaid.cs @@ -76,7 +76,7 @@ public class PhaseBaseAirRaid : AttackPhaseBase, IPhaseAirBattle public string? TouchAircraftFriend => Stage1?.ApiTouchPlane switch { - [EquipmentId id and > 0, ..] => KCDatabase.Instance.MasterEquipments[(int)id].NameEN, + [EquipmentId id and > 0, ..] => KCDatabase.Instance.MasterEquipments[(int)id]?.NameEN, _ => null, }; public string? TouchAircraftFriendDisplay => TouchAircraftFriend switch @@ -87,7 +87,7 @@ public class PhaseBaseAirRaid : AttackPhaseBase, IPhaseAirBattle public string? TouchAircraftEnemy => Stage1?.ApiTouchPlane switch { - [_, EquipmentId id and > 0, ..] => KCDatabase.Instance.MasterEquipments[(int)id].NameEN, + [_, EquipmentId id and > 0, ..] => KCDatabase.Instance.MasterEquipments[(int)id]?.NameEN, _ => null, }; public string? TouchAircraftEnemyDisplay => TouchAircraftEnemy switch From 82ff2c4a7da3d98b2bea3187a910697b8b5152c0 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 20:43:26 +0900 Subject: [PATCH 24/38] sonar --- .../Models/APIHougeki.cs | 2 +- .../Sortie/Battle/Phase/PhaseFriendlyShelling.cs | 5 +++-- .../Battle/Phase/PhaseFriendlySupportInfo.cs | 15 ++++++++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ElectronicObserver.KancolleApi.Types/Models/APIHougeki.cs b/ElectronicObserver.KancolleApi.Types/Models/APIHougeki.cs index 757856c83..130cf1bf5 100644 --- a/ElectronicObserver.KancolleApi.Types/Models/APIHougeki.cs +++ b/ElectronicObserver.KancolleApi.Types/Models/APIHougeki.cs @@ -5,7 +5,7 @@ namespace ElectronicObserver.KancolleApi.Types.Models; /// /// All values will be null when there's a no attack night battle. -/// eg. sub vs sub +/// e.g. sub vs sub /// public class ApiHougeki { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs index 43c7aab97..40cbdd540 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlyShelling.cs @@ -53,7 +53,7 @@ public PhaseFriendlyShelling(IKCDatabase kcDatabase, ApiFriendlyBattle apiFriend List> defenders = ShellingData.ApiDfList!.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); List> attackEquipments = ShellingData.ApiSiList!.Select(elem => elem.Select(ParseInt).ToList()).ToList(); List> criticals = ShellingData.ApiClList!.Select(elem => elem.Where(e => e != HitType.Invalid).ToList()).ToList(); - List> rawDamages = ShellingData.ApiDamage!.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); + List> rawDamages = ShellingData.ApiDamage!.Select(elem => elem.Where(e => e >= 0).ToList()).ToList(); for (int i = 0; i < attackers.Count; i++) { @@ -63,7 +63,8 @@ public PhaseFriendlyShelling(IKCDatabase kcDatabase, ApiFriendlyBattle apiFriend NightAirAttackFlag = nightAirAttackFlags[i] == -1, AttackType = attackTypes[i], DisplayEquipments = attackEquipments[i] - .Select(i => KcDatabase.MasterEquipments[i]) + .Select(id => KcDatabase.MasterEquipments[id]) + .OfType() .ToList(), }; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs index 9ce637ba6..e534a298d 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs @@ -13,7 +13,7 @@ public class PhaseFriendlySupportInfo : PhaseBase { public override string Title => BattleRes.FriendlyFleet; - private List Ships { get; } = new(); + private List Ships { get; } = []; public string Display => CreateDisplay(); @@ -30,13 +30,14 @@ public PhaseFriendlySupportInfo(ApiFriendlyInfo apiFriendlyInfo) for (int i = 0; i < count; i++) { // this should be impossible - if (apiFriendlyInfo.ApiShipId[i] <= 0) + if (apiFriendlyInfo.ApiShipId[i] <= 0 || + KCDatabase.Instance.MasterShips[(int)apiFriendlyInfo.ApiShipId[i]] is not IShipDataMaster shipData) { Ships.Add(null); continue; } - ShipDataMock ship = new(KCDatabase.Instance.MasterShips[(int)apiFriendlyInfo.ApiShipId[i]]) + ShipDataMock ship = new(shipData) { Level = apiFriendlyInfo.ApiShipLv[i], HPCurrent = apiFriendlyInfo.ApiNowhps[i], @@ -44,7 +45,11 @@ public PhaseFriendlySupportInfo(ApiFriendlyInfo apiFriendlyInfo) .Append(apiFriendlyInfo.ApiSlotEx[i]) .Select(id => id switch { - > 0 => new EquipmentDataMock(KCDatabase.Instance.MasterEquipments[(int)id]), + > 0 => KCDatabase.Instance.MasterEquipments[(int)id] switch + { + IEquipmentDataMaster eq => new EquipmentDataMock(eq), + _ => null, + }, _ => null, }) .Cast() @@ -55,7 +60,7 @@ public PhaseFriendlySupportInfo(ApiFriendlyInfo apiFriendlyInfo) ship.TorpedoModernized += apiFriendlyInfo.ApiParam[i][1] - ship.TorpedoBase; ship.AAModernized += apiFriendlyInfo.ApiParam[i][2] - ship.AABase; ship.ArmorModernized += apiFriendlyInfo.ApiParam[i][3] - ship.ArmorBase; - + Ships.Add(ship); } } From f39de66fd8ad153fb6253297255127c27a2440d5 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 21:35:11 +0900 Subject: [PATCH 25/38] refactor --- .../Sortie/Battle/Phase/PhaseInitial.cs | 108 +++++++----------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index a755edca3..b0303b557 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -253,35 +253,7 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, IBattleApiRespo .Zip(battle.ApiShipLv, (id, level) => (Id: id, Level: level)) .Zip(battle.ApiESlot, (t, equipment) => (t.Id, t.Level, Equipment: equipment)) .Zip(battle.ApiENowhps, (t, hp) => (t.Id, t.Level, t.Equipment, Hp: hp)) - .Select(t => t.Id switch - { - > 0 => new ShipDataMock(KcDatabase.MasterShips[t.Id]) - { - HPCurrent = t.Hp switch - { - JsonElement { ValueKind: JsonValueKind.Number } n => n.GetInt32(), - JsonElement { ValueKind: JsonValueKind.String } => KcDatabase.MasterShips[t.Id].HPMin, - _ => throw new NotImplementedException(), - }, - Level = t.Level, - Condition = 49, - SlotInstance = t.Equipment - .Select(id => id switch - { - > 0 => new EquipmentDataMock(KcDatabase.MasterEquipments[id]), - _ => null, - }) - .Cast() - .ToList(), - CanBeTargeted = t.Hp switch - { - JsonElement { ValueKind: JsonValueKind.Number } => true, - JsonElement { ValueKind: JsonValueKind.String } => false, - _ => throw new NotImplementedException(), - }, - }, - _ => null, - }) + .Select(t => MakeShip(KcDatabase, t.Id, t.Level, t.Equipment, t.Hp)) .Concat(Enumerable.Repeat((IShipData?)null, 6)) .Take(6) .ToList(); @@ -360,29 +332,7 @@ public PhaseInitial(IKCDatabase kcDatabase, BattleFleets fleets, ApiDestructionB .Zip(battle.ApiShipLv, (id, level) => (Id: id, Level: level)) .Zip(battle.ApiESlot, (t, equipment) => (t.Id, t.Level, Equipment: equipment)) .Zip(battle.ApiENowhps, (t, hp) => (t.Id, t.Level, t.Equipment, Hp: hp)) - .Select(t => t.Id switch - { - > 0 => new ShipDataMock(KcDatabase.MasterShips[t.Id]) - { - HPCurrent = t.Hp switch - { - JsonElement { ValueKind: JsonValueKind.Number } n => n.GetInt32(), - JsonElement { ValueKind: JsonValueKind.String } => KcDatabase.MasterShips[t.Id].HPMin, - _ => throw new NotImplementedException(), - }, - Level = t.Level, - Condition = 49, - SlotInstance = t.Equipment - .Select(id => id switch - { - > 0 => new EquipmentDataMock(KcDatabase.MasterEquipments[id]), - _ => null, - }) - .Cast() - .ToList(), - }, - _ => null, - }) + .Select(t => MakeShip(KcDatabase, t.Id, t.Level, t.Equipment, t.Hp)) .Concat(Enumerable.Repeat((IShipData?)null, 6)) .Take(6) .ToList(); @@ -430,27 +380,47 @@ private static void Escape(IFleetData? fleet, List? escapeIndexes) .Zip(battle.ApiShipLvCombined, (id, level) => (Id: id, Level: level)) .Zip(battle.ApiESlotCombined, (t, equipment) => (t.Id, t.Level, Equipment: equipment)) .Zip(battle.ApiENowhpsCombined, (t, hp) => (t.Id, t.Level, t.Equipment, Hp: hp)) - .Select(t => t.Id switch + .Select(t => MakeShip(KcDatabase, t.Id, t.Level, t.Equipment, t.Hp)) + .Concat(Enumerable.Repeat((IShipData?)null, 6)) + .Take(6) + .ToList(); + + private static ShipDataMock? MakeShip(IKCDatabase db, int shipId, int level, List equipmentIds, object hp) + { + if (shipId <= 0) return null; + + IShipDataMaster? ship = db.MasterShips[shipId]; + + if(ship is null) return null; + + ShipDataMock mock = new ShipDataMock(ship) { - > 0 => new ShipDataMock(KcDatabase.MasterShips[t.Id]) + HPCurrent = hp switch { - HPCurrent = t.Hp, - Level = t.Level, - Condition = 49, - SlotInstance = t.Equipment - .Select(id => id switch + int i => i, + JsonElement { ValueKind: JsonValueKind.Number } n => n.GetInt32(), + JsonElement { ValueKind: JsonValueKind.String } => ship.HPMin, + _ => throw new NotImplementedException(), + }, + Level = level, + Condition = 49, + SlotInstance = equipmentIds + .Select(id => id switch + { + > 0 => db.MasterEquipments[id] switch { - > 0 => new EquipmentDataMock(KcDatabase.MasterEquipments[id]), + IEquipmentDataMaster eq => new EquipmentDataMock(eq), _ => null, - }) - .Cast() - .ToList(), - }, - _ => null, - }) - .Concat(Enumerable.Repeat((IShipData?)null, 6)) - .Take(6) - .ToList(); + }, + _ => null, + }) + .Cast() + .ToList(), + CanBeTargeted = hp is not JsonElement { ValueKind: JsonValueKind.String }, + }; + + return mock; + } private static void SetEnemyRange(List ships) { From dd85cb014d82b435138e7de11051752906fa5667 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 21:37:57 +0900 Subject: [PATCH 26/38] simplify code --- .../Sortie/Battle/Phase/PhaseInitial.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs index b0303b557..50ab0e739 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseInitial.cs @@ -391,9 +391,9 @@ private static void Escape(IFleetData? fleet, List? escapeIndexes) IShipDataMaster? ship = db.MasterShips[shipId]; - if(ship is null) return null; + if (ship is null) return null; - ShipDataMock mock = new ShipDataMock(ship) + return new(ship) { HPCurrent = hp switch { @@ -418,8 +418,6 @@ private static void Escape(IFleetData? fleet, List? escapeIndexes) .ToList(), CanBeTargeted = hp is not JsonElement { ValueKind: JsonValueKind.String }, }; - - return mock; } private static void SetEnemyRange(List ships) @@ -430,7 +428,7 @@ private static void SetEnemyRange(List ships) s.Range = Math.Max(s.MasterShip.Range, s.AllSlotInstance switch { - [] => 0, + [] => 0, _ => s.AllSlotInstance.Max(e => e?.MasterEquipment.Range ?? 0), }); } From 3ad39af0f503fe41d54cb64d05779f6d0511f87d Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 21:45:24 +0900 Subject: [PATCH 27/38] sonar --- .../Sortie/Battle/Phase/PhaseNightBattle.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs index 21985e83e..e1ad17dea 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs @@ -37,7 +37,7 @@ public PhaseNightBattle(IKCDatabase kcDatabase, List apiAtEflag, List List> defenders = apiDfList.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); List> attackEquipments = apiSiList.Select(elem => elem.Select(ParseInt).ToList()).ToList(); List> criticals = apiClList.Select(elem => elem.Where(e => e != HitType.Invalid).ToList()).ToList(); - List> rawDamages = apiDamage.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); + List> rawDamages = apiDamage.Select(elem => elem.Where(e => e >= 0).ToList()).ToList(); for (int i = 0; i < attackers.Count; i++) { @@ -47,7 +47,8 @@ public PhaseNightBattle(IKCDatabase kcDatabase, List apiAtEflag, List NightAirAttackFlag = nightAirAttackFlags[i] == -1, AttackType = attackTypes[i], DisplayEquipments = attackEquipments[i] - .Select(i => KcDatabase.MasterEquipments[i]) + .Select(id => KcDatabase.MasterEquipments[id]) + .OfType() .ToList(), }; From cd1fd9a457c3394d8802d28ffeb074748d0d9faf Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 21:46:09 +0900 Subject: [PATCH 28/38] sonar --- .../SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs index ff6812a0c..e8f909155 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShelling.cs @@ -46,7 +46,7 @@ public PhaseShelling(IKCDatabase kcDatabase, ApiHougeki1 shellingData, DayShelli List> defenders = ShellingData.ApiDfList.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); List> attackEquipments = ShellingData.ApiSiList.Select(elem => elem.Select(ParseInt).ToList()).ToList(); List> criticalFlags = ShellingData.ApiClList.Select(elem => elem.Where(e => e != HitType.Invalid).ToList()).ToList(); - List> rawDamages = ShellingData.ApiDamage.Select(elem => elem.Where(e => e != -1).ToList()).ToList(); + List> rawDamages = ShellingData.ApiDamage.Select(elem => elem.Where(e => e >= 0).ToList()).ToList(); for (int i = 0; i < attackers.Count; i++) { @@ -56,6 +56,7 @@ public PhaseShelling(IKCDatabase kcDatabase, ApiHougeki1 shellingData, DayShelli AttackType = attackTypes[i], DisplayEquipments = attackEquipments[i] .Select(id => KcDatabase.MasterEquipments[id]) + .OfType() .ToList(), }; From 48df4793c44061a662ab6c14583697448bf830ac Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 22:18:22 +0900 Subject: [PATCH 29/38] sonar --- .../Window/Wpf/Battle/BattleViewModel.cs | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index 8a8f62803..c46330893 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -204,7 +204,7 @@ public BattleViewModel() : base("Battle", "Battle", IconContent.FormBattle) o.ApiReqPractice_MidnightBattle.ResponseReceived += Updated; o.ApiReqPractice_BattleResult.ResponseReceived += Updated; - PropertyChanged += (sender, args) => + PropertyChanged += (_, args) => { if (args.PropertyName is not nameof(CompactMode)) return; @@ -223,7 +223,7 @@ public BattleViewModel() : base("Battle", "Battle", IconContent.FormBattle) [RelayCommand] private void ShowBattleDetail() { - BattleManager? bm = KCDatabase.Instance.Battle; + BattleManager bm = KCDatabase.Instance.Battle; if (bm.FirstBattle is null) return; @@ -242,6 +242,7 @@ private void ShowBattleResult() PlayerFleetVisible = true; } + [SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] private void Updated(string apiname, dynamic data) { KCDatabase db = KCDatabase.Instance; @@ -258,7 +259,7 @@ private void Updated(string apiname, dynamic data) case "api_req_map/start": case "api_req_map/next": - if (!bm.Compass.HasAirRaid) + if (bm.FirstBattle is null) { ViewVisible = false; break; @@ -538,7 +539,7 @@ private void Updated(string apiname, dynamic data) /// private void SetFormation(BattleManager bm) { - if (bm.FirstBattle is not FirstBattleData { Searching: { } searching }) return; + if (bm.FirstBattle is not { Searching: { } searching }) return; FormationFriendText = Constants.GetFormationShort(searching.PlayerFormationType); FormationEnemyText = Constants.GetFormationShort(searching.EnemyFormationType); @@ -602,7 +603,7 @@ private void SetFormation(BattleManager bm) /// /// 索敵結果を設定します。 /// - private void SetSearchingResult(FirstBattleData bd) + private void SetSearchingResult(FirstBattleData? bd) { if (bd is not { Searching: { } searching }) return; @@ -989,8 +990,10 @@ private void ClearAerialWarfare() /// /// 両軍のHPゲージを設定します。 /// - private void SetHPBar(BattleData bd) + private void SetHPBar(BattleData? bd) { + if (bd is null) return; + bool isPractice = bd.IsPractice; bool isFriendCombined = bd.IsFriendCombined; bool isEnemyCombined = bd.IsEnemyCombined; @@ -1054,7 +1057,7 @@ void SetEnemyBackground(int index) } else { - IShipData ship = bd.FleetsBeforeBattle.Fleet.MembersInstance[i]; + IShipData ship = bd.FleetsBeforeBattle.Fleet.MembersInstance[i]!; name = ship.NameWithLevel; isEscaped = bd.FleetsBeforeBattle.Fleet.EscapedShipList.Contains(ship.MasterID); isLandBase = ship.MasterShip.IsLandBase; @@ -1094,7 +1097,7 @@ void SetEnemyBackground(int index) if (initial.EnemyInitialHPs[i] != -1) { - IShipData ship = bd.Initial.EnemyMembersInstance[i]; + IShipData ship = bd.Initial.EnemyMembersInstance[i]!; EnableHPBar(refindex, ship.HPCurrent, resultHPs[refindex], ship.HPMax, ship.CanBeTargeted); var bar = HPBars[refindex]; @@ -1292,7 +1295,7 @@ void SetEnemyBackground(int index) } } - private bool _hpBarMoved = false; + private bool _hpBarMoved; /// /// 味方遊撃部隊7人目のHPゲージ(通常時は連合艦隊第二艦隊旗艦のHPゲージ)を移動します。 /// @@ -1336,9 +1339,13 @@ private void SetDamageRate(BattleManager bm) if (bm.IsBaseAirRaid) { - int kind = bm.Compass.AirRaidDamageKind; + int kind = bm.Compass!.AirRaidDamageKind; WinRankText = Constants.GetAirRaidDamageShort(kind); - WinRankForeColor = (1 <= kind && kind <= 3) ? WinRankColor_Lose : WinRankColor_Win; + WinRankForeColor = kind switch + { + >= 1 and <= 3 => WinRankColor_Lose, + _ => WinRankColor_Win, + }; } else { @@ -1350,9 +1357,11 @@ private void SetDamageRate(BattleManager bm) /// /// 夜戦における各種表示を設定します。 /// - private void SetNightBattleEvent(PhaseNightInitial pd) + private void SetNightBattleEvent(PhaseNightInitial? pd) { - IFleetData fleet = pd.FleetsBeforePhase!.Fleet; + if (pd?.FleetsBeforePhase is null) return; + + IFleetData fleet = pd.FleetsBeforePhase.Fleet; //味方探照灯判定 { @@ -1452,8 +1461,11 @@ private void SetMVPShip(BattleManager bm) { bool isCombined = bm.IsCombinedBattle; - BattleData bd = bm.SecondBattle ?? bm.FirstBattle; - BattleResult br = bm.Result; + BattleData? bd = bm.SecondBattle ?? bm.FirstBattle; + BattleResult? br = bm.Result; + + if (bd is null) return; + if (br is null) return; IFleetData friend = bd.FleetsBeforeBattle.Fleet; IFleetData? escort = isCombined switch @@ -1462,7 +1474,7 @@ private void SetMVPShip(BattleManager bm) _ => bd.FleetsBeforeBattle.EscortFleet, }; - for (int i = 0; i < friend.Members.Count; i++) + for (int i = 0; i < friend.Members!.Count; i++) { if (friend.EscapedShipList.Contains(friend.Members[i])) { @@ -1480,7 +1492,7 @@ private void SetMVPShip(BattleManager bm) if (escort != null) { - for (int i = 0; i < escort.Members.Count; i++) + for (int i = 0; i < escort.Members!.Count; i++) { if (escort.EscapedShipList.Contains(escort.Members[i])) { From 382a17d0df249f7769109ffcdfe60036603e998f Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 22:30:41 +0900 Subject: [PATCH 30/38] sonar --- .../Sortie/Battle/Phase/PhaseNightBattle.cs | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs index e1ad17dea..b3870d0c5 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattle.cs @@ -83,33 +83,7 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List { if (atk.AttackType.IsSpecialAttack()) { - List attackers = atk.AttackType switch - { - NightAttackKind.CutinZuiun => Enumerable.Repeat(atk.Attacker.Index, 2).ToList(), - _ => atk.AttackType.SpecialAttackIndexes(), - }; - - int fleetCount = KCDatabase.Instance.Fleet.Fleets.Values - .Count(f => f.IsInSortie); - - for (int i = 0; i < atk.Defenders.Count; i++) - { - int attackerIndex = attackers[i]; - - PhaseNightBattleAttack comboAttack = atk with - { - Attacker = fleetCount switch - { - 2 => new(attackerIndex + 6, FleetFlag.Player), - _ => new(attackerIndex, FleetFlag.Player), - }, - Defenders = [atk.Defenders[i]], - }; - - AttackDisplays.Add(new PhaseNightBattleAttackViewModel(FleetsAfterPhase, comboAttack, comboAttack.Defenders.First().Defender)); - AddDamage(FleetsAfterPhase, atk.Defenders[i].Defender, atk.Defenders[i].Damage); - damages[comboAttack.Attacker.ToFlatIndex()] += comboAttack.Defenders.Sum(d => d.Damage); - } + ProcessSpecialAttack(atk, damages, FleetsAfterPhase); } else { @@ -124,4 +98,35 @@ public override BattleFleets EmulateBattle(BattleFleets battleFleets, List return FleetsAfterPhase.Clone(); } + + private void ProcessSpecialAttack(PhaseNightBattleAttack atk, List damages, BattleFleets fleetsAfterPhase) + { + List attackers = atk.AttackType switch + { + NightAttackKind.CutinZuiun => Enumerable.Repeat(atk.Attacker.Index, 2).ToList(), + _ => atk.AttackType.SpecialAttackIndexes(), + }; + + int fleetCount = KCDatabase.Instance.Fleet.Fleets.Values + .Count(f => f.IsInSortie); + + for (int i = 0; i < atk.Defenders.Count; i++) + { + int attackerIndex = attackers[i]; + + PhaseNightBattleAttack comboAttack = atk with + { + Attacker = fleetCount switch + { + 2 => new(attackerIndex + 6, FleetFlag.Player), + _ => new(attackerIndex, FleetFlag.Player), + }, + Defenders = [atk.Defenders[i]], + }; + + AttackDisplays.Add(new PhaseNightBattleAttackViewModel(fleetsAfterPhase, comboAttack, comboAttack.Defenders.First().Defender)); + AddDamage(fleetsAfterPhase, atk.Defenders[i].Defender, atk.Defenders[i].Damage); + damages[comboAttack.Attacker.ToFlatIndex()] += comboAttack.Defenders.Sum(d => d.Damage); + } + } } From 324309883af937a0e4e7fdf9299d2d42f94a0373 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 23:02:31 +0900 Subject: [PATCH 31/38] add mvp prediction --- .../DataExport/DataExportHelper.cs | 4 +- .../Sortie/Battle/BattleData.cs | 47 +++++++++++++++++++ .../Phase/AirBaseRaidAttackViewModel.cs | 2 +- .../Battle/Phase/AirBattleAttackViewModel.cs | 4 +- .../Sortie/Battle/Phase/AttackPhaseBase.cs | 1 - .../Battle/Phase/AttackViewModelBase.cs | 3 ++ .../PhaseFriendNightBattleAttackViewModel.cs | 5 +- .../Phase/PhaseNightBattleAttackViewModel.cs | 4 +- .../Phase/PhaseShellingAttackViewModel.cs | 4 +- .../Phase/PhaseSupportAttackViewModel.cs | 4 +- .../Phase/PhaseTorpedoAttackViewModel.cs | 4 +- .../Window/Wpf/Battle/BattleViewModel.cs | 9 ++-- 12 files changed, 76 insertions(+), 15 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs index deb06640c..57ad442c3 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/DataExport/DataExportHelper.cs @@ -641,7 +641,7 @@ void ProcessData(IFleetData fleet, IFleetData attackerFleet, FleetFlag fleetFlag HitType.Critical => 1, _ => 0, }, - Damage = attackDisplay?.Damage ?? 0, + Damage = (int?)attackDisplay?.Damage ?? 0, Protected = attackDisplay?.GuardsFlagship switch { true => 1, @@ -830,7 +830,7 @@ private static AirBattleExportModel MakeAirBattleExport(BattleNode node, HitType.Critical => 1, _ => 0, }, - Damage = attackDisplay?.Damage ?? 0, + Damage = (int?)attackDisplay?.Damage ?? 0, Protected = attackDisplay?.GuardsFlagship switch { true => 1, diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs index c10957d3f..ca086fe93 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/BattleData.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using ElectronicObserver.KancolleApi.Types.Interfaces; @@ -44,6 +45,52 @@ private static IEnumerable GetHpList(IFleetData? fleet) => .Take(Math.Max(fleet.MembersInstance.Count, 6)) ?? Enumerable.Repeat(0, 6); + public IEnumerable MvpShipIndexes() + { + if (FleetsBeforeBattle.Fleet.Members is null) return [0]; + + List<(int? Index, int Damage)> damages = Phases + .OfType() + .SelectMany(p => p.AttackDisplays) + .Where(a => a.AttackerIndex?.FleetFlag is FleetFlag.Player) + .Where(a => a.AttackerIndex?.Index < FleetsBeforeBattle.Fleet.Members.Count) + .GroupBy(a => a.AttackerIndex?.Index) + .Select(g => (g.Key, (int)g.Sum(a => a.Damage))) + .ToList(); + + int max = damages.Select(d => d.Damage).Max(); + + if (max is 0) return [0]; + + return damages + .Where(d => d.Damage == max) + .Select(d => d.Index) + .OfType(); + } + + public IEnumerable MvpShipCombinedIndexes() + { + if (FleetsBeforeBattle.EscortFleet?.Members is null) return [0]; + + List<(int? Index, int Damage)> damages = Phases + .OfType() + .SelectMany(p => p.AttackDisplays) + .Where(a => a.AttackerIndex?.FleetFlag is FleetFlag.Player) + .Where(a => a.AttackerIndex?.Index > 5) + .GroupBy(a => a.AttackerIndex?.Index) + .Select(g => (g.Key, (int)g.Sum(a => a.Damage))) + .ToList(); + + int max = damages.Select(d => d.Damage).Max(); + + if (max is 0) return [0]; + + return damages + .Where(d => d.Damage == max) + .Select(d => d.Index - 6) + .OfType(); + } + public IEnumerable AirBaseBeforeAfter => FleetsBeforeBattle.AirBases .Zip(FleetsAfterBattle.AirBases, (before, after) => (Before: before, After: after)) .Select((t, i) => new AirBaseBeforeAfter(i, t.Before, t.After)); diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs index 02f65ee74..9e44eeb15 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBaseRaidAttackViewModel.cs @@ -23,7 +23,7 @@ public sealed class AirBaseRaidAttackViewModel : AttackViewModelBase private int DefenderHpBeforeAttack { get; } public override string DefenderDisplay { get; } - private double Damage { get; } + public override double Damage { get; } private HitType HitType { get; } private AirAttack AttackType { get; } public override string DamageDisplay { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs index c389242a7..78ca8b46b 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AirBattleAttackViewModel.cs @@ -23,7 +23,7 @@ public sealed class AirBattleAttackViewModel : AttackViewModelBase public int DefenderHpBeforeAttack { get; } public override string DefenderDisplay { get; } - public int Damage { get; } + public override double Damage { get; } public HitType HitType { get; } public AirAttack AttackType { get; } private IEquipmentData? UsedDamecon { get; } @@ -47,7 +47,7 @@ public AirBattleAttackViewModel(BattleFleets fleets, int waveIndex, AirBattleAtt DefenderHpBeforeAttack = Defender.HPCurrent; - int hpAfterAttacks = Math.Max(0, DefenderHpBeforeAttack - Damage); + int hpAfterAttacks = Math.Max(0, DefenderHpBeforeAttack - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs index a0db9a560..bf3ee41b9 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackPhaseBase.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using ElectronicObserver.Window.Dialog.BattleDetail; using System.Linq; namespace ElectronicObserver.Window.Tools.SortieRecordViewer.Sortie.Battle.Phase; diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs index 0bdaa1471..7917c2a9e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/AttackViewModelBase.cs @@ -1,4 +1,5 @@ using System.Linq; +using ElectronicObserver.Utility.Data; using ElectronicObserverTypes; using ElectronicObserverTypes.Attacks; @@ -15,6 +16,8 @@ public abstract class AttackViewModelBase public abstract BattleIndex DefenderIndex { get; } public abstract string DefenderDisplay { get; } + public abstract double Damage { get; } + // \u2192 = → public string AttackerDefenderDisplay => $"{AttackerDisplay} \u2192 {DefenderDisplay}"; public abstract string DamageDisplay { get; } diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs index 437924fdb..5dca25f3e 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendNightBattleAttackViewModel.cs @@ -18,6 +18,7 @@ public sealed class PhaseFriendNightBattleAttackViewModel : AttackViewModelBase private List DefenderHpBeforeAttacks { get; } = []; public override string DefenderDisplay { get; } + public override double Damage { get; } private List Attacks { get; } private IEquipmentData? UsedDamecon { get; } public override string DamageDisplay { get; } @@ -44,6 +45,7 @@ public PhaseFriendNightBattleAttackViewModel(BattleFleets fleets, BattleIndex at CriticalFlag = d.CriticalFlag, }) .ToList(); + Damage = Attacks.Sum(a => a.Damage); AttackerHpBeforeAttack = Attacker.HPCurrent; DefenderHpBeforeAttacks.Add(Defender.HPCurrent); @@ -53,7 +55,8 @@ public PhaseFriendNightBattleAttackViewModel(BattleFleets fleets, BattleIndex at DefenderHpBeforeAttacks.Add(Math.Max(0, DefenderHpBeforeAttacks[^1] - nightAttack.Damage)); } - int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - Attacks.Sum(a => a.Damage)); + + int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs index de78aef1f..adea8c9d0 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseNightBattleAttackViewModel.cs @@ -18,6 +18,7 @@ public sealed class PhaseNightBattleAttackViewModel : AttackViewModelBase public List DefenderHpBeforeAttacks { get; } = []; public override string DefenderDisplay { get; } + public override double Damage { get; } public NightAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } @@ -50,6 +51,7 @@ public PhaseNightBattleAttackViewModel(BattleFleets fleets, PhaseNightBattleAtta }) .ToList(); DisplayEquipment = attack.DisplayEquipments; + Damage = Attacks.Sum(a => a.Damage); AttackerHpBeforeAttack = Attacker.HPCurrent; DefenderHpBeforeAttacks.Add(Defender.HPCurrent); @@ -59,7 +61,7 @@ public PhaseNightBattleAttackViewModel(BattleFleets fleets, PhaseNightBattleAtta DefenderHpBeforeAttacks.Add(Math.Max(0, DefenderHpBeforeAttacks[^1] - nightAttack.Damage)); } - int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - Attacks.Sum(a => a.Damage)); + int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs index d0707b252..0937d2001 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseShellingAttackViewModel.cs @@ -19,6 +19,7 @@ public sealed class PhaseShellingAttackViewModel : AttackViewModelBase public List DefenderHpBeforeAttacks { get; } = []; public override string DefenderDisplay { get; } + public override double Damage { get; } public DayAttackKind AttackType { get; } public List DisplayEquipment { get; } public List Attacks { get; } @@ -48,6 +49,7 @@ public PhaseShellingAttackViewModel(BattleFleets fleets, PhaseShellingAttack att }) .ToList(); DisplayEquipment = attack.DisplayEquipments; + Damage = Attacks.Sum(a => a.Damage); AttackerHpBeforeAttack = Attacker.HPCurrent; DefenderHpBeforeAttacks.Add(Defender.HPCurrent); @@ -57,7 +59,7 @@ public PhaseShellingAttackViewModel(BattleFleets fleets, PhaseShellingAttack att DefenderHpBeforeAttacks.Add(Math.Max(0, DefenderHpBeforeAttacks[^1] - dayAttack.Damage)); } - int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - Attacks.Sum(a => a.Damage)); + int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs index 8d28d15e1..07aa07ab7 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseSupportAttackViewModel.cs @@ -15,6 +15,7 @@ public sealed class PhaseSupportAttackViewModel : AttackViewModelBase private List DefenderHpBeforeAttacks { get; } = []; public override string DefenderDisplay { get; } + public override double Damage { get; } private SupportType AttackType { get; } private List Attacks { get; } private IEquipmentData? UsedDamecon { get; } @@ -37,6 +38,7 @@ public PhaseSupportAttackViewModel(BattleFleets fleets, PhaseSupportAttack attac CriticalFlag = d.CriticalFlag, }) .ToList(); + Damage = Attacks.Sum(a => a.Damage); DefenderHpBeforeAttacks.Add(Defender.HPCurrent); @@ -45,7 +47,7 @@ public PhaseSupportAttackViewModel(BattleFleets fleets, PhaseSupportAttack attac DefenderHpBeforeAttacks.Add(Math.Max(0, DefenderHpBeforeAttacks[^1] - supportAttack.Damage)); } - int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - Attacks.Sum(a => a.Damage)); + int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs index eb03c666c..672a71cc0 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseTorpedoAttackViewModel.cs @@ -19,6 +19,7 @@ public sealed class PhaseTorpedoAttackViewModel : AttackViewModelBase private List DefenderHpBeforeAttacks { get; } = []; public override string DefenderDisplay { get; } + public override double Damage { get; } private DayAttackKind AttackType { get; } public List Attacks { get; } private IEquipmentData? UsedDamecon { get; } @@ -46,6 +47,7 @@ public PhaseTorpedoAttackViewModel(BattleFleets fleets, PhaseTorpedoAttack attac CriticalFlag = d.CriticalFlag, }) .ToList(); + Damage = Attacks.Sum(a => a.Damage); AttackerHpBeforeAttack = Attacker.HPCurrent; DefenderHpBeforeAttacks.Add(Defender.HPCurrent); @@ -55,7 +57,7 @@ public PhaseTorpedoAttackViewModel(BattleFleets fleets, PhaseTorpedoAttack attac DefenderHpBeforeAttacks.Add(Math.Max(0, DefenderHpBeforeAttacks[^1] - dayAttack.Damage)); } - int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - Attacks.Sum(a => a.Damage)); + int hpAfterAttacks = Math.Max(0, Defender.HPCurrent - (int)Damage); if (hpAfterAttacks <= 0 && GetDamecon(Defender) is { } damecon) { diff --git a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs index c46330893..c89ad5420 100644 --- a/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Battle/BattleViewModel.cs @@ -774,6 +774,7 @@ private void SetAerialWarfare(IPhaseAirBattle? phaseJet, IPhaseAirBattle? phase1 /// 噴式航空戦のデータ。発生していなければ null /// 第一次航空戦(通常航空戦)のデータ。 /// 第二次航空戦のデータ。発生していなければ null + [SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] private void SetAerialWarfare(IPhaseAirBattle? phaseJet, IPhaseAirBattle? phase1, IPhaseAirBattle? phase2) { List phases = new() @@ -990,6 +991,7 @@ private void ClearAerialWarfare() /// /// 両軍のHPゲージを設定します。 /// + [SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] private void SetHPBar(BattleData? bd) { if (bd is null) return; @@ -1278,20 +1280,18 @@ void SetEnemyBackground(int index) if (!isBaseAirRaid) { - /* todo - foreach (int i in bd.MVPShipIndexes) + foreach (int i in bd.MvpShipIndexes()) { HPBars[BattleIndex.Get(BattleSides.FriendMain, i)].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; } if (isFriendCombined) { - foreach (int i in bd.MVPShipCombinedIndexes) + foreach (int i in bd.MvpShipCombinedIndexes()) { HPBars[BattleIndex.Get(BattleSides.FriendEscort, i)].BackColor = Configuration.Config.UI.Battle_ColorHPBarsMVP; } } - */ } } @@ -1457,6 +1457,7 @@ private void SetNightBattleEvent(PhaseNightInitial? pd) /// 戦闘終了後に、MVP艦の表示を更新します。 /// /// 戦闘データ。 + [SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "todo")] private void SetMVPShip(BattleManager bm) { bool isCombined = bm.IsCombinedBattle; From d3da166ee23c88e1cca37bcac649f5724c0423c2 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 23:14:12 +0900 Subject: [PATCH 32/38] sonar --- ElectronicObserver/Data/CompassData.cs | 2 +- .../Resource/Record/EnemyFleetRecord.cs | 2 +- .../Window/Wpf/Compass/CompassViewModel.cs | 107 +++++++++--------- 3 files changed, 53 insertions(+), 58 deletions(-) diff --git a/ElectronicObserver/Data/CompassData.cs b/ElectronicObserver/Data/CompassData.cs index 26f99fc25..2ed28f061 100644 --- a/ElectronicObserver/Data/CompassData.cs +++ b/ElectronicObserver/Data/CompassData.cs @@ -233,7 +233,7 @@ public bool WhirlpoolRadarFlag /// /// 能動分岐の選択肢 /// - public ReadOnlyCollection RouteChoices + public ReadOnlyCollection? RouteChoices { get { diff --git a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs index 38bb1d7f3..11c022e76 100644 --- a/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs +++ b/ElectronicObserver/Resource/Record/EnemyFleetRecord.cs @@ -216,7 +216,7 @@ public override void RegisterEvents() } - public EnemyFleetElement this[ulong i] + public EnemyFleetElement? this[ulong i] { get { diff --git a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs index 451a9b361..621f92297 100644 --- a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Windows.Media; @@ -98,28 +99,26 @@ public CompassViewModel() : base("Compass", "Compass", IconContent.FormCompass) private void Updated(string apiname, dynamic data) { - System.Drawing.Color GetColorFromEventKind(int kind) + System.Drawing.Color GetColorFromEventKind(int kind) => kind switch { - switch (kind) - { - case 0: - case 1: - default: //昼夜戦・その他 - return Utility.Configuration.Config.UI.ForeColor; - case 2: - case 3: //夜戦・夜昼戦 - return Utility.Configuration.Config.UI.Compass_ColorTextEventKind3; - case 4: //航空戦 - case 6: //長距離空襲戦 - return Utility.Configuration.Config.UI.Compass_ColorTextEventKind6; - case 5: // 敵連合 - return Utility.Configuration.Config.UI.Compass_ColorTextEventKind5; - case 7: // 夜昼戦(対連合艦隊) - return Utility.Configuration.Config.UI.Compass_ColorTextEventKind3; - case 8: // レーダー射撃 - return Utility.Configuration.Config.UI.Compass_ColorTextEventKind3; - } - } + //夜戦・夜昼戦 + 2 or 3 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind3, + + // 航空戦・長距離空襲戦 + 4 or 6 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind6, + + // 敵連合 + 5 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind5, + + // 夜昼戦(対連合艦隊) + 7 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind3, + + // レーダー射撃 + 8 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind3, + + //昼夜戦・その他 + _ => Utility.Configuration.Config.UI.ForeColor + }; if (apiname == "api_port/port") { @@ -142,6 +141,8 @@ System.Drawing.Color GetColorFromEventKind(int kind) } else { + Debug.Assert(Db.Battle.Compass is not null); + CompassData compass = Db.Battle.Compass; // ex: world 5-5 @@ -237,8 +238,8 @@ System.Drawing.Color GetColorFromEventKind(int kind) case 3: //渦潮 { int materialmax = KCDatabase.Instance.Fleet.Fleets.Values - .Where(f => f != null && f.IsInSortie) - .SelectMany(f => f.MembersWithoutEscaped) + .Where(f => f is { IsInSortie: true }) + .SelectMany(f => f.MembersWithoutEscaped!) .Max(s => { if (s == null) return 0; @@ -282,31 +283,16 @@ System.Drawing.Color GetColorFromEventKind(int kind) case 1: //イベントなし case 6: //気のせいだった - switch (compass.EventKind) + eventkind = compass.EventKind switch { - - case 0: //気のせいだった - default: - break; - case 1: - eventkind = FormCompass.NoEnemySighted; - break; - case 2: - eventkind = FormCompass.BranchChoice; - break; - case 3: - eventkind = FormCompass.CalmSea; - break; - case 4: - eventkind = FormCompass.CalmStrait; - break; - case 5: - eventkind = FormCompass.NeedToBeCareful; - break; - case 6: - eventkind = FormCompass.CalmSea2; - break; - } + 1 => FormCompass.NoEnemySighted, + 2 => FormCompass.BranchChoice, + 3 => FormCompass.CalmSea, + 4 => FormCompass.CalmStrait, + 5 => FormCompass.NeedToBeCareful, + 6 => FormCompass.CalmSea2, + _ => eventkind + }; if (compass.RouteChoices != null) { @@ -355,7 +341,6 @@ System.Drawing.Color GetColorFromEventKind(int kind) break; - case 4: //航空戦 default: UpdateEnemyFleet(); break; @@ -400,6 +385,8 @@ System.Drawing.Color GetColorFromEventKind(int kind) private void UpdateEnemyFleet() { + Debug.Assert(Db.Battle.Compass is not null); + CompassData compass = Db.Battle.Compass; CurrentViewModel = EnemyListViewModel; @@ -433,11 +420,11 @@ private void UpdateEnemyFleet() return a.Formation - b.Formation; }); - NextEnemyFleetCandidate(0); + NextEnemyFleetCandidate(); } } - private void NextEnemyFleetCandidate(int offset) + private void NextEnemyFleetCandidate() { if (_enemyFleetCandidate == null || _enemyFleetCandidate.Count == 0) return; @@ -575,8 +562,11 @@ private void UpdateEnemyFleetInstant(bool isPractice = false) if (!bm.IsPractice) { - EnemyFleetRecord.EnemyFleetElement efcurrent = EnemyFleetRecord.EnemyFleetElement.CreateFromCurrentState(); - EnemyFleetRecord.EnemyFleetElement efrecord = RecordManager.Instance.EnemyFleet[efcurrent.FleetID]; + EnemyFleetRecord.EnemyFleetElement? efcurrent = EnemyFleetRecord.EnemyFleetElement.CreateFromCurrentState(); + + Debug.Assert(efcurrent is not null); + + EnemyFleetRecord.EnemyFleetElement? efrecord = RecordManager.Instance.EnemyFleet[efcurrent.FleetID]; if (efrecord != null) { TextEnemyFleetNameText = KCDatabase.Instance.Translation.Operation.FleetName(efrecord.FleetName); @@ -589,13 +579,18 @@ private void UpdateEnemyFleetInstant(bool isPractice = false) { int air = Calculator.GetAirSuperiority(enemies, slots); - TextAirSuperiorityText = isPractice ? - air.ToString() + " ~ " + Calculator.GetAirSuperiorityAtMaxLevel(enemies, slots).ToString() : - air.ToString(); + TextAirSuperiorityText = isPractice switch + { + true => air + " ~ " + Calculator.GetAirSuperiorityAtMaxLevel(enemies, slots), + _ => air.ToString(), + }; if (enemies.Select(id => KCDatabase.Instance.MasterShips[id]) - .Any(ship => ship != null && RecordManager.Instance.ShipParameter[ship.ShipID]?.Aircraft == null)) + .OfType() + .Any(ship => RecordManager.Instance.ShipParameter[ship.ShipID]?.Aircraft == null)) + { TextAirSuperiorityText += "?"; + } TextAirSuperiorityToolTip = GetAirSuperiorityString(isPractice ? 0 : air); } From f4b071f35e3d824fc6faa70e90e9ed7530157c46 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 23:41:48 +0900 Subject: [PATCH 33/38] sonar --- ElectronicObserver/Data/FleetData.cs | 8 +- .../InformationView/InformationViewModel.cs | 194 +++++++++--------- 2 files changed, 103 insertions(+), 99 deletions(-) diff --git a/ElectronicObserver/Data/FleetData.cs b/ElectronicObserver/Data/FleetData.cs index 7c4bf89c4..645dd1ee0 100644 --- a/ElectronicObserver/Data/FleetData.cs +++ b/ElectronicObserver/Data/FleetData.cs @@ -45,22 +45,22 @@ public class FleetData : APIWrapper, IIdentifiable, IFleetData public DateTime ExpeditionTime { get; internal set; } - private int[] _members; + private int[]? _members; /// /// 艦隊メンバー(艦船ID) /// - public ReadOnlyCollection Members => Array.AsReadOnly(_members); + public ReadOnlyCollection Members => Array.AsReadOnly(_members ?? []); /// /// 艦隊メンバー(艦船データ) /// - public ReadOnlyCollection? MembersInstance + public ReadOnlyCollection? MembersInstance { get { if (_members == null) return null; - IShipData[] ships = new IShipData[_members.Length]; + IShipData?[] ships = new IShipData[_members.Length]; for (int i = 0; i < ships.Length; i++) { ships[i] = KCDatabase.Instance.Ships[_members[i]]; diff --git a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs index 7ca462943..7e6353a75 100644 --- a/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs +++ b/ElectronicObserver/Window/Wpf/InformationView/InformationViewModel.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Windows; @@ -70,7 +73,7 @@ private void Updated(string apiname, dynamic data) if (_inSortie != null) { - Text = GetConsumptionResource(data); + Text = GetConsumptionResource(); } _inSortie = null; @@ -94,7 +97,7 @@ private void Updated(string apiname, dynamic data) break; case "api_get_member/mapinfo": - Text = GetMapGauge(data); + Text = GetMapGauge(); break; case "api_get_member/mission": @@ -154,7 +157,7 @@ private void Updated(string apiname, dynamic data) break; case "api_req_practice/battle": - _inSortie = [ KCDatabase.Instance.Battle.FirstBattle.Initial.FriendFleetID ]; + _inSortie = [ KCDatabase.Instance.Battle.FirstBattle!.Initial.FriendFleetID ]; break; } @@ -186,38 +189,50 @@ private string GetPracticeEnemyInfo(dynamic data) // 練巡ボーナス計算 - きたない - var fleet = KCDatabase.Instance.Fleet[1]; - if (fleet.MembersInstance.Any(s => s != null && s.MasterShip.ShipType == ShipTypes.TrainingCruiser)) + FleetData fleet = KCDatabase.Instance.Fleet[1]; + + Debug.Assert(fleet.MembersInstance is not null); + + if (fleet.MembersInstance.Any(s => s is { MasterShip.ShipType: ShipTypes.TrainingCruiser })) { - var members = fleet.MembersInstance; - var subCT = members.Skip(1).Where(s => s != null && s.MasterShip.ShipType == ShipTypes.TrainingCruiser); + ReadOnlyCollection? members = fleet.MembersInstance; + List subCT = members + .Skip(1) + .OfType() + .Where(s => s is { MasterShip.ShipType: ShipTypes.TrainingCruiser }) + .ToList(); double bonus; // 旗艦が練巡 - if (members[0] != null && members[0].MasterShip.ShipType == ShipTypes.TrainingCruiser) + if (members[0] is { MasterShip.ShipType: ShipTypes.TrainingCruiser} ship) { - int level = members[0].Level; + int level = ship.Level; - if (subCT != null && subCT.Any()) + if (subCT.Any()) { - // 旗艦+随伴 - if (level < 10) bonus = 1.10; - else if (level < 30) bonus = 1.13; - else if (level < 60) bonus = 1.16; - else if (level < 100) bonus = 1.20; - else bonus = 1.25; - + bonus = level switch + { + // 旗艦+随伴 + < 10 => 1.10, + < 30 => 1.13, + < 60 => 1.16, + < 100 => 1.20, + _ => 1.25, + }; } else { - // 旗艦のみ - if (level < 10) bonus = 1.05; - else if (level < 30) bonus = 1.08; - else if (level < 60) bonus = 1.12; - else if (level < 100) bonus = 1.15; - else bonus = 1.20; + bonus = level switch + { + // 旗艦のみ + < 10 => 1.05, + < 30 => 1.08, + < 60 => 1.12, + < 100 => 1.15, + _ => 1.20, + }; } } @@ -226,24 +241,29 @@ private string GetPracticeEnemyInfo(dynamic data) int level = subCT.Max(s => s.Level); - if (subCT.Count() > 1) + if (subCT.Count > 1) { - // 随伴複数 - if (level < 10) bonus = 1.04; - else if (level < 30) bonus = 1.06; - else if (level < 60) bonus = 1.08; - else if (level < 100) bonus = 1.12; - else bonus = 1.175; - + bonus = level switch + { + // 随伴複数 + < 10 => 1.04, + < 30 => 1.06, + < 60 => 1.08, + < 100 => 1.12, + _ => 1.175, + }; } else { - // 随伴単艦 - if (level < 10) bonus = 1.03; - else if (level < 30) bonus = 1.05; - else if (level < 60) bonus = 1.07; - else if (level < 100) bonus = 1.10; - else bonus = 1.15; + bonus = level switch + { + // 随伴単艦 + < 10 => 1.03, + < 30 => 1.05, + < 60 => 1.07, + < 100 => 1.10, + _ => 1.15, + }; } } @@ -257,18 +277,17 @@ private string GetPracticeEnemyInfo(dynamic data) } private string GetAlbumInfo(dynamic data) { + StringBuilder sb = new(); - StringBuilder sb = new StringBuilder(); - - if (data != null && data.api_list() && data.api_list != null) + if (data != null && data!.api_list() && data!.api_list != null) { - if (data.api_list[0].api_yomi()) + if (data!.api_list[0].api_yomi()) { //艦娘図鑑 const int bound = 70; // 図鑑1ページあたりの艦船数 int startIndex = (((int)data.api_list[0].api_index_no - 1) / bound) * bound + 1; - bool[] flags = Enumerable.Repeat(false, bound).ToArray(); + bool[] flags = Enumerable.Repeat(false, bound).ToArray(); sb.AppendLine(GeneralRes.DamagedArtUnseen); @@ -310,7 +329,7 @@ private string GetAlbumInfo(dynamic data) //装備図鑑 const int bound = 70; // 図鑑1ページあたりの装備数 int startIndex = (((int)data.api_list[0].api_index_no - 1) / bound) * bound + 1; - bool[] flags = Enumerable.Repeat(false, bound).ToArray(); + bool[] flags = Enumerable.Repeat(false, bound).ToArray(); foreach (dynamic elem in data.api_list) { @@ -323,7 +342,7 @@ private string GetAlbumInfo(dynamic data) { if (!flags[i]) { - IEquipmentDataMaster eq = KCDatabase.Instance.MasterEquipments.Values.FirstOrDefault(s => s.AlbumNo == startIndex + i); + IEquipmentDataMaster? eq = KCDatabase.Instance.MasterEquipments.Values.FirstOrDefault(s => s.AlbumNo == startIndex + i); if (eq != null) { sb.AppendLine(eq.NameEN); @@ -336,34 +355,9 @@ private string GetAlbumInfo(dynamic data) return sb.ToString(); } - - private string GetCreateItemInfo(dynamic data) - { - - if ((int)data.api_create_flag == 0) - { - - StringBuilder sb = new StringBuilder(); - sb.AppendLine(GeneralRes.DevelopmentFailed); - sb.AppendLine(data.api_fdata); - - IEquipmentDataMaster eqm = KCDatabase.Instance.MasterEquipments[int.Parse(((string)data.api_fdata).Split(",".ToCharArray())[1])]; - if (eqm != null) - sb.AppendLine(eqm.NameEN); - - - return sb.ToString(); - - } - else - return ""; - } - - - private string GetMapGauge(dynamic data) + private string GetMapGauge() { - - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new(); sb.AppendLine(GeneralRes.MapGauges); string rpcMapInfo = ""; @@ -418,7 +412,9 @@ private string GetMapGauge(dynamic data) private enum MissionState { + // ReSharper disable once UnusedMember.Local New, + // ReSharper disable once UnusedMember.Local NotCompleted, Completed } @@ -494,11 +490,10 @@ private string GetSupplyInformation(dynamic data) } - private string GetConsumptionResource(dynamic data) + private string GetConsumptionResource() { - StringBuilder sb = new StringBuilder(); - var material = KCDatabase.Instance.Material; + MaterialData material = KCDatabase.Instance.Material; int fuel_diff = material.Fuel - _prevResource[0], @@ -506,11 +501,13 @@ private string GetConsumptionResource(dynamic data) steel_diff = material.Steel - _prevResource[2], bauxite_diff = material.Bauxite - _prevResource[3]; + Debug.Assert(_inSortie is not null); - var ships = KCDatabase.Instance.Fleet.Fleets.Values + List ships = KCDatabase.Instance.Fleet.Fleets.Values .Where(f => _inSortie.Contains(f.FleetID)) - .SelectMany(f => f.MembersInstance) - .Where(s => s != null); + .SelectMany(f => f.MembersInstance!) + .OfType() + .ToList(); int fuel_supply = ships.Sum(s => s.SupplyFuel); int ammo = ships.Sum(s => s.SupplyAmmo); @@ -530,21 +527,26 @@ private string GetConsumptionResource(dynamic data) } + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] private void CheckSallyArea() { // only check if there's any event maps // this function shouldn't get called outside of events so the check should be pointless // if (KCDatabase.Instance.MapArea.Values.Any(m => m.ID > 20)) return; - IEnumerable> group; - - if (KCDatabase.Instance.Fleet.CombinedFlag != 0) - group = new[] { KCDatabase.Instance.Fleet[1].MembersInstance.Concat(KCDatabase.Instance.Fleet[2].MembersInstance).Where(s => s != null) }; - else - group = KCDatabase.Instance.Fleet.Fleets.Values - .Where(f => f?.ExpeditionState == 0) - .Select(f => f.MembersInstance.Where(s => s != null)); - + IEnumerable> group = KCDatabase.Instance.Fleet.CombinedFlag switch + { + 0 => KCDatabase.Instance.Fleet.Fleets.Values + .Where(f => f.ExpeditionState == 0) + .Select(f => f.MembersInstance!.OfType()), + + _ => + [ + KCDatabase.Instance.Fleet[1].MembersInstance! + .Concat(KCDatabase.Instance.Fleet[2].MembersInstance!) + .OfType() + ], + }; group = group.Where(ss => ss.All(s => s.RepairingDockID == -1) && @@ -553,21 +555,28 @@ private void CheckSallyArea() if (group.Any()) { - var freeShips = group.SelectMany(f => f).Where(s => s.SallyArea == 0); + IEnumerable freeShips = group + .SelectMany(f => f) + .Where(s => s.SallyArea == 0); Text = InformationResources.FleetTagWarning + string.Join("\r\n", freeShips.Select(s => s.NameWithLevel)); if (Utility.Configuration.Config.Control.ShowSallyAreaAlertDialog) + { MessageBox.Show(InformationResources.FleetTagAlertDialogText, InformationResources.FleetTagAlertDialogCaption, MessageBoxButton.OK, MessageBoxImage.Warning); + } } } private void CheckExpedition(int missionID, int fleetID) { - var fleet = KCDatabase.Instance.Fleet[fleetID]; - var result = MissionClearCondition.Check(missionID, fleet); - var mission = KCDatabase.Instance.Mission[missionID]; + FleetData fleet = KCDatabase.Instance.Fleet[fleetID]; + MissionClearCondition.MissionClearConditionResult result = MissionClearCondition.Check(missionID, fleet); + MissionData? mission = KCDatabase.Instance.Mission[missionID]; + + Debug.Assert(fleet.MembersInstance is not null); + Debug.Assert(mission is not null); if (!result.IsSuceeded) { @@ -592,9 +601,4 @@ private void RecordMaterials() _prevResource[2] = material.Steel; _prevResource[3] = material.Bauxite; } - - protected string GetPersistString() - { - return "Information"; - } } From 642c47372ae127cb48e96c8816540ec3bd5acc34 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 23:48:23 +0900 Subject: [PATCH 34/38] sonar --- ElectronicObserver/Data/CompassData.cs | 10 ++++++---- .../Window/Wpf/Compass/CompassViewModel.cs | 2 +- ElectronicObserverTypes/Data/IDDictionary.cs | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ElectronicObserver/Data/CompassData.cs b/ElectronicObserver/Data/CompassData.cs index 2ed28f061..ffa54e25c 100644 --- a/ElectronicObserver/Data/CompassData.cs +++ b/ElectronicObserver/Data/CompassData.cs @@ -114,7 +114,7 @@ public int FlavorTextType /// /// 「気のせいだった」セルにおける特殊メッセージ なければ null /// - public string FlavorText + public string? FlavorText { get { @@ -159,7 +159,7 @@ public IEnumerable GetItems yield break; // item.IsArray だと参照できないため - if (!(((dynamic)item).IsArray)) + if (!(item.IsArray)) { yield return new GetItemData((int)item.api_usemst, (int)item.api_id, (int)item.api_getcount); @@ -255,7 +255,9 @@ public string[] RouteChoicesDisplay { get { - var nodes = new string[RouteChoices.Count]; + if (RouteChoices is null) return []; + + string[] nodes = new string[RouteChoices.Count]; for (int i = 0; i < RouteChoices.Count; i++) { nodes[i] = KCDatabase.Instance.Translation.Destination.CellDisplay(MapAreaID, MapInfoID, RouteChoices[i]); @@ -314,7 +316,7 @@ public int AirReconnaissanceResult /// /// 基地空襲戦データ /// - public dynamic AirRaidData => HasAirRaid ? RawData.api_destruction_battle : null; + public dynamic? AirRaidData => HasAirRaid ? RawData.api_destruction_battle : null; diff --git a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs index 621f92297..6252904aa 100644 --- a/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs +++ b/ElectronicObserver/Window/Wpf/Compass/CompassViewModel.cs @@ -99,7 +99,7 @@ public CompassViewModel() : base("Compass", "Compass", IconContent.FormCompass) private void Updated(string apiname, dynamic data) { - System.Drawing.Color GetColorFromEventKind(int kind) => kind switch + static System.Drawing.Color GetColorFromEventKind(int kind) => kind switch { //夜戦・夜昼戦 2 or 3 => Utility.Configuration.Config.UI.Compass_ColorTextEventKind3, diff --git a/ElectronicObserverTypes/Data/IDDictionary.cs b/ElectronicObserverTypes/Data/IDDictionary.cs index 4208c95b1..4b30e8e54 100644 --- a/ElectronicObserverTypes/Data/IDDictionary.cs +++ b/ElectronicObserverTypes/Data/IDDictionary.cs @@ -71,7 +71,9 @@ public bool TryGetValue(int key, out TData value) public IEnumerable Values => dict.Values; +#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). public TData? this[int key] => dict.ContainsKey(key) ? dict[key] : null; +#pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). public int Count => dict.Count; From 8c6d3a4ddc0d8525124e3058040de5030bafdf08 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 1 Aug 2024 23:59:37 +0900 Subject: [PATCH 35/38] undo changes --- ElectronicObserver/Data/CompassData.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ElectronicObserver/Data/CompassData.cs b/ElectronicObserver/Data/CompassData.cs index ffa54e25c..26f99fc25 100644 --- a/ElectronicObserver/Data/CompassData.cs +++ b/ElectronicObserver/Data/CompassData.cs @@ -114,7 +114,7 @@ public int FlavorTextType /// /// 「気のせいだった」セルにおける特殊メッセージ なければ null /// - public string? FlavorText + public string FlavorText { get { @@ -159,7 +159,7 @@ public IEnumerable GetItems yield break; // item.IsArray だと参照できないため - if (!(item.IsArray)) + if (!(((dynamic)item).IsArray)) { yield return new GetItemData((int)item.api_usemst, (int)item.api_id, (int)item.api_getcount); @@ -233,7 +233,7 @@ public bool WhirlpoolRadarFlag /// /// 能動分岐の選択肢 /// - public ReadOnlyCollection? RouteChoices + public ReadOnlyCollection RouteChoices { get { @@ -255,9 +255,7 @@ public string[] RouteChoicesDisplay { get { - if (RouteChoices is null) return []; - - string[] nodes = new string[RouteChoices.Count]; + var nodes = new string[RouteChoices.Count]; for (int i = 0; i < RouteChoices.Count; i++) { nodes[i] = KCDatabase.Instance.Translation.Destination.CellDisplay(MapAreaID, MapInfoID, RouteChoices[i]); @@ -316,7 +314,7 @@ public int AirReconnaissanceResult /// /// 基地空襲戦データ /// - public dynamic? AirRaidData => HasAirRaid ? RawData.api_destruction_battle : null; + public dynamic AirRaidData => HasAirRaid ? RawData.api_destruction_battle : null; From 5034f373e577cf71dbb8c990abb455103d098385 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Fri, 2 Aug 2024 00:00:56 +0900 Subject: [PATCH 36/38] undo --- ElectronicObserver/Data/FleetData.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ElectronicObserver/Data/FleetData.cs b/ElectronicObserver/Data/FleetData.cs index 645dd1ee0..7c4bf89c4 100644 --- a/ElectronicObserver/Data/FleetData.cs +++ b/ElectronicObserver/Data/FleetData.cs @@ -45,22 +45,22 @@ public class FleetData : APIWrapper, IIdentifiable, IFleetData public DateTime ExpeditionTime { get; internal set; } - private int[]? _members; + private int[] _members; /// /// 艦隊メンバー(艦船ID) /// - public ReadOnlyCollection Members => Array.AsReadOnly(_members ?? []); + public ReadOnlyCollection Members => Array.AsReadOnly(_members); /// /// 艦隊メンバー(艦船データ) /// - public ReadOnlyCollection? MembersInstance + public ReadOnlyCollection? MembersInstance { get { if (_members == null) return null; - IShipData?[] ships = new IShipData[_members.Length]; + IShipData[] ships = new IShipData[_members.Length]; for (int i = 0; i < ships.Length; i++) { ships[i] = KCDatabase.Instance.Ships[_members[i]]; From 532cc61dbda99a27ab5319b1db0a4f5515a17034 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Sat, 3 Aug 2024 12:28:12 +0900 Subject: [PATCH 37/38] remove useless code --- .../Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs index 514ea8865..5e2119c83 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Node/BattleNode.cs @@ -107,7 +107,7 @@ public void AddResult(ISortieBattleResultApi result) bool damageTaken = hpBeforeBattle > hpAfterBattle; - return (WinRank: BattleResult?.Rank, damageTaken) switch + return (BattleResult?.Rank, damageTaken) switch { ("S", false) => "SS", _ => BattleResult?.Rank, From 4541ad2d6068e0822dcd49c376ffb8a597e0fa37 Mon Sep 17 00:00:00 2001 From: MyAngelKamikaze Date: Thu, 26 Sep 2024 19:36:04 +0900 Subject: [PATCH 38/38] fix --- .../Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs index 1240aa092..869759bde 100644 --- a/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs +++ b/ElectronicObserver/Window/Tools/SortieRecordViewer/Sortie/Battle/Phase/PhaseFriendlySupportInfo.cs @@ -60,11 +60,6 @@ public PhaseFriendlySupportInfo(ApiFriendlyInfo apiFriendlyInfo) ArmorBase = apiFriendlyInfo.ApiParam[i][3], }; - ship.FirepowerModernized += apiFriendlyInfo.ApiParam[i][0] - ship.FirepowerBase; - ship.TorpedoModernized += apiFriendlyInfo.ApiParam[i][1] - ship.TorpedoBase; - ship.AAModernized += apiFriendlyInfo.ApiParam[i][2] - ship.AABase; - ship.ArmorModernized += apiFriendlyInfo.ApiParam[i][3] - ship.ArmorBase; - Ships.Add(ship); } }