// Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
// \r
-// This program is part of KancolleSniffer.\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
//\r
-// KancolleSniffer is free software: you can redistribute it and/or modify\r
-// it under the terms of the GNU General Public License as published by\r
-// the Free Software Foundation, either version 3 of the License, or\r
-// (at your option) any later version.\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
//\r
-// This program is distributed in the hope that it will be useful,\r
-// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-// GNU General Public License for more details.\r
-//\r
-// You should have received a copy of the GNU General Public License\r
-// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
\r
using System.Collections.Generic;\r
using System.Linq;\r
B,\r
C,\r
D,\r
- E\r
+ E,\r
+ }\r
+\r
+ public enum BattleState\r
+ {\r
+ None,\r
+ Day,\r
+ Night,\r
+ Result\r
}\r
\r
public class BattleInfo\r
{\r
- private readonly ShipMaster _shipMaster;\r
private readonly ShipInfo _shipInfo;\r
private readonly ItemInfo _itemInfo;\r
private int _fleet;\r
private Record[] _friend;\r
private Record[] _guard;\r
private int[] _enemyHp;\r
+ private int[] _enemyGuardHp;\r
private int[] _enemyStartHp;\r
+ private int[] _enemyGuardStartHp;\r
private readonly List<int> _escapingShips = new List<int>();\r
+ private int _flagshipRecoveryType;\r
\r
- public const int IncollectFighterPowerFlag = 0x10000;\r
- public bool InBattle { get; set; }\r
+ public BattleState BattleState { get; set; }\r
public string Formation { get; private set; }\r
- public int EnemyFighterPower { get; private set; }\r
- public bool HasDamagedShip { get; set; }\r
- public string[] DamagedShipNames { get; private set; }\r
+ public string EnemyFighterPower { get; private set; }\r
public int AirControlLevel { get; private set; }\r
public BattleResultRank ResultRank { get; private set; }\r
+ public ShipStatus[] EnemyResultStatus { get; private set; }\r
+ public List<AirBattleResult> AirBattleResults { get; } = new List<AirBattleResult>();\r
+\r
\r
- public BattleInfo(ShipMaster shipMaster, ShipInfo shipInfo, ItemInfo itemInfo)\r
+ public BattleInfo(ShipInfo shipInfo, ItemInfo itemInfo)\r
{\r
- _shipMaster = shipMaster;\r
_shipInfo = shipInfo;\r
_itemInfo = itemInfo;\r
}\r
\r
- public void InspectBattle(dynamic json)\r
+ public void InspectBattle(dynamic json, string url)\r
{\r
- InBattle = true;\r
Formation = FormationName(json);\r
EnemyFighterPower = CalcEnemyFighterPower(json);\r
AirControlLevel = CheckAirControlLevel(json);\r
ShowResult(false); // 昼戦の結果を夜戦のときに表示する\r
SetupResult(json);\r
if (IsNightBattle(json))\r
- CalcHougekiDamage(json.api_hougeki, _friend, _enemyHp);\r
+ {\r
+ BattleState = BattleState.Night;\r
+ CalcHougekiDamage(json.api_hougeki,\r
+ _guard.Length > 0 ? _guard : _friend,\r
+ json.api_active_deck() && json.api_active_deck[1] != 1 ? _enemyGuardHp : _enemyHp);\r
+ }\r
else\r
- CalcDamage(json);\r
- ClearOverKill(_enemyHp);\r
- ResultRank = CalcResultRank();\r
+ {\r
+ BattleState = BattleState.Day;\r
+ CalcDamage(json, url.EndsWith("battle_water"));\r
+ }\r
+ ClearEnemyOverKill();\r
+ ResultRank = url.EndsWith("ld_airbattle") ? CalcLdAirBattleRank() : CalcResultRank();\r
+ }\r
+\r
+ private void ClearEnemyOverKill()\r
+ {\r
+ _enemyHp = _enemyHp.Select(hp => hp < 0 ? 0 : hp).ToArray();\r
+ _enemyGuardHp = _enemyGuardHp.Select(hp => hp < 0 ? 0 : hp).ToArray();\r
}\r
\r
- private int DeckId(dynamic json)\r
+ public void InspectMapNext(string request)\r
+ {\r
+ var type = HttpUtility.ParseQueryString(request)["api_recovery_type"];\r
+ if (type == null)\r
+ return;\r
+ _flagshipRecoveryType = int.Parse(type);\r
+ }\r
+\r
+ private bool IsNightBattle(dynamic json) => json.api_hougeki();\r
+\r
+ public static int DeckId(dynamic json)\r
{\r
if (json.api_dock_id()) // 昼戦はtypoしている\r
return (int)json.api_dock_id - 1;\r
- if (json.api_deck_id is string) // 通常の夜戦では文字列\r
+ if (json.api_deck_id is string) // é\80\9a常ã\81®å¤\9cæ\88¦ã\81¨é\80£å\90\88è\89¦é\9a\8a(å\91³æ\96¹ã\81®ã\81¿)ã\81§ã\81¯æ\96\87å\97å\88\97\r
return int.Parse(json.api_deck_id) - 1;\r
return (int)json.api_deck_id - 1;\r
}\r
{\r
if (_friend != null)\r
return;\r
- var combined = json.api_nowhps_combined();\r
var nowhps = (int[])json.api_nowhps;\r
- _fleet = combined ? 0 : DeckId(json);\r
+ _fleet = DeckId(json);\r
var fstats = _shipInfo.GetShipStatuses(_fleet);\r
- _friend = Record.Setup(\r
- nowhps, (int[])json.api_maxhps,\r
- fstats.Select(s => s.Slot).ToArray(),\r
- fstats.Select(s => s.SlotEx).ToArray(),\r
- _itemInfo);\r
- _enemyHp = nowhps.Skip(7).TakeWhile(hp => hp != -1).ToArray();\r
+ FlagshipRecovery(fstats[0]);\r
+ _friend = Record.Setup(fstats);\r
+ _enemyHp = nowhps.Skip(7).ToArray();\r
_enemyStartHp = (int[])_enemyHp.Clone();\r
- if (combined)\r
+ EnemyResultStatus =\r
+ (from id in\r
+ json.api_ship_ke_combined()\r
+ ? ((int[])json.api_ship_ke).Skip(1).Concat(((int[])json.api_ship_ke_combined).Skip(1))\r
+ : ((int[])json.api_ship_ke).Skip(1)\r
+ select new ShipStatus {Id = id, Spec = _shipInfo.GetSpec(id)}).ToArray();\r
+ _guard = new Record[0];\r
+ _enemyGuardHp = new int[0];\r
+ _enemyGuardStartHp = new int[0];\r
+ if (!json.api_nowhps_combined())\r
+ return;\r
+ var combined = (int[])json.api_nowhps_combined;\r
+ if (combined[1] != -1) // 味方が連合艦隊\r
+ _guard = Record.Setup(_shipInfo.GetShipStatuses(1));\r
+ if (combined.Length > 7) // 敵が連合艦隊\r
{\r
- var gstats = _shipInfo.GetShipStatuses(1);\r
- _guard = Record.Setup(\r
- (int[])json.api_nowhps_combined,\r
- (int[])json.api_maxhps_combined,\r
- gstats.Select(s => s.Slot).ToArray(),\r
- gstats.Select(s => s.SlotEx).ToArray(),\r
- _itemInfo);\r
+ _enemyGuardHp =\r
+ ((int[])json.api_nowhps_combined).\r
+ Skip(7).ToArray();\r
+ _enemyGuardStartHp = (int[])_enemyGuardHp.Clone();\r
}\r
- else\r
+ }\r
+\r
+ private void FlagshipRecovery(ShipStatus flagship)\r
+ {\r
+ switch (_flagshipRecoveryType)\r
{\r
- _guard = new Record[0];\r
+ case 0:\r
+ return;\r
+ case 1:\r
+ flagship.NowHp = flagship.MaxHp / 2;\r
+ ConsumeSlotItem(flagship, 42); // ダメコン\r
+ break;\r
+ case 2:\r
+ flagship.NowHp = flagship.MaxHp;\r
+ ConsumeSlotItem(flagship, 43); // 女神\r
+ break;\r
+ }\r
+ if (_flagshipRecoveryType != 0)\r
+ _shipInfo.SetBadlyDamagedShips();\r
+ _flagshipRecoveryType = 0;\r
+ }\r
+\r
+ private static void ConsumeSlotItem(ShipStatus ship, int id)\r
+ {\r
+ if (ship.SlotEx.Spec.Id == id)\r
+ {\r
+ ship.SlotEx = new ItemStatus();\r
+ return;\r
+ }\r
+ for (var i = 0; i < ship.Slot.Length; i++)\r
+ {\r
+ if (ship.Slot[i].Spec.Id == id)\r
+ {\r
+ ship.Slot[i] = new ItemStatus();\r
+ break;\r
+ }\r
}\r
}\r
\r
return (int)stage1.api_disp_seiku;\r
}\r
\r
- private int CalcEnemyFighterPower(dynamic json)\r
+ private string CalcEnemyFighterPower(dynamic json)\r
{\r
- var missing = 0;\r
+ var missing = "";\r
var maxEq = ((int[])json.api_ship_ke).Skip(1).SelectMany(id =>\r
{\r
- var r = _shipMaster[id].MaxEq;\r
+ var r = _shipInfo.GetSpec(id).MaxEq;\r
if (r != null)\r
return r;\r
- missing = IncollectFighterPowerFlag;\r
+ missing = "+";\r
return new int[5];\r
- });\r
+ }).ToArray();\r
var equips = ((int[][])json.api_eSlot).SelectMany(x => x);\r
return (from slot in equips.Zip(maxEq, (id, max) => new {id, max})\r
- let spec = _itemInfo.GetSpecByItemId(slot.id)\r
- where spec.CanAirCombat\r
- select (int)Floor(spec.AntiAir * Sqrt(slot.max))).DefaultIfEmpty().Sum() | missing;\r
+ let spec = _itemInfo.GetSpecByItemId(slot.id)\r
+ where spec.CanAirCombat\r
+ select (int)Floor(spec.AntiAir * Sqrt(slot.max))).DefaultIfEmpty().Sum() + missing;\r
}\r
\r
private void CalcDamage(dynamic json, bool surfaceFleet = false)\r
{\r
- var combined = json.api_nowhps_combined();\r
- if (json.api_kouku.api_stage3 != null)\r
- CalcSimpleDamage(json.api_kouku.api_stage3, _friend, _enemyHp);\r
- if (json.api_kouku.api_stage3_combined() && json.api_kouku.api_stage3_combined != null)\r
- CalcSimpleDamage(json.api_kouku.api_stage3_combined.api_fdam, _guard);\r
+ AirBattleResults.Clear();\r
+ var fc = _guard.Length > 0;\r
+ var ec = _enemyGuardHp.Length > 0;\r
+ var both = fc && ec;\r
+ if (json.api_air_base_injection())\r
+ {\r
+ AddAirBattleResult(json.api_air_base_injection, "AB噴式");\r
+ CalcKoukuDamage(json.api_air_base_injection);\r
+ }\r
+ if (json.api_injection_kouku())\r
+ {\r
+ AddAirBattleResult(json.api_injection_kouku, "噴式");\r
+ CalcKoukuDamage(json.api_injection_kouku);\r
+ }\r
+ if (json.api_air_base_attack())\r
+ CalcAirBaseAttackDamage(json.api_air_base_attack);\r
+ if (json.api_kouku())\r
+ {\r
+ AddAirBattleResult(json.api_kouku, "航空戦");\r
+ CalcKoukuDamage(json.api_kouku);\r
+ }\r
if (json.api_kouku2()) // 航空戦2回目\r
{\r
- if (json.api_kouku2.api_stage3 != null)\r
- CalcSimpleDamage(json.api_kouku2.api_stage3, _friend, _enemyHp);\r
- if (json.api_kouku2.api_stage3_combined() && json.api_kouku2.api_stage3_combined != null)\r
- CalcSimpleDamage(json.api_kouku2.api_stage3_combined.api_fdam, _guard);\r
+ AddAirBattleResult(json.api_kouku2, "航空戦2");\r
+ CalcKoukuDamage(json.api_kouku2);\r
}\r
if (!json.api_opening_atack()) // 航空戦のみ\r
return;\r
if (json.api_support_info() && json.api_support_info != null)\r
CalcSupportDamage(json.api_support_info);\r
+ if (json.api_opening_taisen() && json.api_opening_taisen != null)\r
+ {\r
+ if (json.api_opening_taisen.api_at_eflag())\r
+ {\r
+ CalcCombinedHougekiDamage(json.api_opening_taisen, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcHougekiDamage(json.api_opening_taisen,\r
+ fc ? _guard : _friend, // 先制対潜攻撃の対象は護衛\r
+ _enemyHp);\r
+ }\r
+ }\r
if (json.api_opening_atack != null)\r
{\r
- var friend = combined ? _guard : _friend; // 雷撃の対象は護衛\r
- CalcSimpleDamage(json.api_opening_atack, friend, _enemyHp);\r
+ if (both)\r
+ {\r
+ CalcSimpleDamage(json.api_opening_atack, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcSimpleDamage(json.api_opening_atack,\r
+ fc ? _guard : _friend, // 雷撃の対象は護衛\r
+ _enemyHp, _enemyGuardHp);\r
+ }\r
}\r
- if (json.api_hougeki1 != null)\r
+ if (json.api_hougeki1() && json.api_hougeki1 != null)\r
{\r
- var friend = combined && !surfaceFleet ? _guard : _friend; // 空母機動部隊は一巡目が護衛\r
- CalcHougekiDamage(json.api_hougeki1, friend, _enemyHp);\r
+ if (json.api_hougeki1.api_at_eflag())\r
+ {\r
+ CalcCombinedHougekiDamage(json.api_hougeki1, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcHougekiDamage(json.api_hougeki1,\r
+ fc && !surfaceFleet ? _guard : _friend, // 空母機動部隊は一巡目が護衛\r
+ ec ? _enemyGuardHp : _enemyHp); // 敵連合艦隊は一巡目が護衛\r
+ }\r
}\r
if (json.api_hougeki2() && json.api_hougeki2 != null)\r
{\r
- CalcHougekiDamage(json.api_hougeki2, _friend, _enemyHp);\r
+ if (json.api_hougeki2.api_at_eflag())\r
+ {\r
+ CalcCombinedHougekiDamage(json.api_hougeki2, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcHougekiDamage(json.api_hougeki2, _friend, _enemyHp);\r
+ }\r
}\r
if (json.api_hougeki3() && json.api_hougeki3 != null)\r
{\r
- var friend = combined && surfaceFleet ? _guard : _friend; // 水上打撃部隊は三順目が護衛\r
- CalcHougekiDamage(json.api_hougeki3, friend, _enemyHp);\r
+ if (json.api_hougeki3.api_at_eflag())\r
+ {\r
+ CalcCombinedHougekiDamage(json.api_hougeki3, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcHougekiDamage(json.api_hougeki3,\r
+ fc && surfaceFleet ? _guard : _friend, // 水上打撃部隊は三順目が護衛\r
+ _enemyHp);\r
+ }\r
}\r
if (json.api_raigeki() && json.api_raigeki != null)\r
{\r
- var friend = combined ? _guard : _friend;\r
- CalcSimpleDamage(json.api_raigeki, friend, _enemyHp);\r
+ if (both)\r
+ {\r
+ CalcSimpleDamage(json.api_raigeki, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+ }\r
+ else\r
+ {\r
+ CalcSimpleDamage(json.api_raigeki,\r
+ fc ? _guard : _friend, // 雷撃の対象は護衛\r
+ _enemyHp, _enemyGuardHp);\r
+ }\r
}\r
}\r
\r
private void CalcSupportDamage(dynamic json)\r
{\r
if (json.api_support_hourai != null)\r
- CalcSimpleDamage(json.api_support_hourai.api_damage, _enemyHp);\r
+ {\r
+ CalcSimpleDamage(json.api_support_hourai.api_damage, _enemyHp, _enemyGuardHp);\r
+ }\r
else if (json.api_support_airatack != null)\r
{\r
- var stage3 = json.api_support_airatack.api_stage3;\r
- if (stage3 != null)\r
- CalcSimpleDamage(stage3.api_edam, _enemyHp);\r
+ CalcSimpleDamage(json.api_support_airatack.api_stage3.api_edam, _enemyHp, _enemyGuardHp);\r
}\r
}\r
\r
- private bool IsNightBattle(dynamic json) => json.api_hougeki();\r
+ private void CalcAirBaseAttackDamage(dynamic json)\r
+ {\r
+ var i = 1;\r
+ foreach (var entry in json)\r
+ {\r
+ AddAirBattleResult(entry, "基地" + i++);\r
+ CalcKoukuDamage(entry);\r
+ }\r
+ }\r
+\r
+ private void AddAirBattleResult(dynamic json, string phaseName)\r
+ {\r
+ var stage1 = json.api_stage1;\r
+ if (stage1 == null || (stage1.api_f_count == 0 && stage1.api_e_count == 0))\r
+ return;\r
+ AirBattleResults.Add(new AirBattleResult\r
+ {\r
+ PhaseName = phaseName,\r
+ AirControlLevel = json.api_stage1.api_disp_seiku() ? (int)json.api_stage1.api_disp_seiku : 0,\r
+ Stage1 = new AirBattleResult.StageResult\r
+ {\r
+ FriendCount = (int)json.api_stage1.api_f_count,\r
+ FriendLost = (int)json.api_stage1.api_f_lostcount,\r
+ EnemyCount = (int)json.api_stage1.api_e_count,\r
+ EnemyLost = (int)json.api_stage1.api_e_lostcount\r
+ },\r
+ Stage2 = json.api_stage2 == null\r
+ ? new AirBattleResult.StageResult\r
+ {\r
+ FriendCount = 0,\r
+ FriendLost = 0,\r
+ EnemyCount = 0,\r
+ EnemyLost = 0\r
+ }\r
+ : new AirBattleResult.StageResult\r
+ {\r
+ FriendCount = (int)json.api_stage2.api_f_count,\r
+ FriendLost = (int)json.api_stage2.api_f_lostcount,\r
+ EnemyCount = (int)json.api_stage2.api_e_count,\r
+ EnemyLost = (int)json.api_stage2.api_e_lostcount\r
+ }\r
+ });\r
+ }\r
+\r
+ private void CalcKoukuDamage(dynamic json)\r
+ {\r
+ if (!json.api_stage3() || json.api_stage3 == null)\r
+ return;\r
+ CalcSimpleDamage(json.api_stage3, _friend, _enemyHp);\r
+ if (json.api_stage3_combined())\r
+ CalcSimpleDamage(json.api_stage3_combined, _guard, _enemyGuardHp);\r
+ }\r
\r
private void CalcSimpleDamage(dynamic json, Record[] friend, int[] enemy)\r
{\r
+ if (json.api_fdam())\r
+ CalcSimpleDamage(json.api_fdam, friend);\r
+ if (json.api_edam())\r
+ CalcSimpleDamage(json.api_edam, enemy);\r
+ }\r
+\r
+ private void CalcSimpleDamage(dynamic json, Record[] friend, int[] enemy, int[] enemyGuard)\r
+ {\r
CalcSimpleDamage(json.api_fdam, friend);\r
- CalcSimpleDamage(json.api_edam, enemy);\r
+ CalcSimpleDamage(json.api_edam, enemy, enemyGuard);\r
}\r
\r
- private void CalcSimpleDamage(dynamic rawDamage, Record[] result)\r
+ private void CalcSimpleDamage(dynamic json, Record[] friend, Record[] guard, int[] enemy, int[] enemyGuard)\r
+ {\r
+ CalcSimpleDamage(json.api_fdam, friend, guard);\r
+ CalcSimpleDamage(json.api_edam, enemy, enemyGuard);\r
+ }\r
+\r
+ private void CalcSimpleDamage(dynamic rawDamage, Record[] friend, Record[] guard)\r
{\r
var damage = (int[])rawDamage;\r
- for (var i = 0; i < result.Length; i++)\r
- result[i].ApplyDamage(damage[i + 1]);\r
+ for (var i = 0; i < friend.Length; i++)\r
+ friend[i].ApplyDamage(damage[i + 1]);\r
+ for (var i = 0; i < guard.Length; i++)\r
+ guard[i].ApplyDamage(damage[i + 6 + 1]);\r
+ }\r
+\r
+ private void CalcSimpleDamage(dynamic rawDamage, Record[] friend)\r
+ {\r
+ var damage = (int[])rawDamage;\r
+ for (var i = 0; i < friend.Length; i++)\r
+ friend[i].ApplyDamage(damage[i + 1]);\r
+ }\r
+\r
+ private void CalcSimpleDamage(dynamic rawDamage, int[] enemy, int[] enemyGuard)\r
+ {\r
+ var damage = (int[])rawDamage;\r
+ for (var i = 0; i < enemy.Length; i++)\r
+ enemy[i] -= damage[i + 1];\r
+ for (var i = 0; i < enemyGuard.Length; i++)\r
+ enemyGuard[i] -= damage[i + 6 + 1];\r
}\r
\r
private void CalcSimpleDamage(dynamic rawDamage, int[] result)\r
private void CalcHougekiDamage(dynamic hougeki, Record[] friend, int[] enemy)\r
{\r
var targets = ((dynamic[])hougeki.api_df_list).Skip(1).SelectMany(x => (int[])x);\r
- var damages = ((dynamic[])hougeki.api_damage).Skip(1).SelectMany(x => (double[])x);\r
+ var damages = ((dynamic[])hougeki.api_damage).Skip(1).SelectMany(x => (int[])x);\r
foreach (var hit in targets.Zip(damages, (t, d) => new {t, d}))\r
{\r
if (hit.t == -1)\r
continue;\r
if (hit.t <= 6)\r
- friend[hit.t - 1].ApplyDamage((int)hit.d);\r
+ friend[hit.t - 1].ApplyDamage(hit.d);\r
else\r
- enemy[(hit.t - 1) % 6] -= (int)hit.d;\r
+ enemy[(hit.t - 1) % 6] -= hit.d;\r
}\r
}\r
\r
- private void ClearOverKill(int[] result)\r
+ private void CalcCombinedHougekiDamage(dynamic hougeki, Record[] friend, Record[] guard,\r
+ int[] enemy, int[] enemyGuard)\r
{\r
- for (var i = 0; i < result.Length; i++)\r
- if (result[i] < 0)\r
- result[i] = 0;\r
+ var targets = ((dynamic[])hougeki.api_df_list).Skip(1).Select(x => (int[])x);\r
+ var damages = ((dynamic[])hougeki.api_damage).Skip(1).Select(x => (int[])x);\r
+ var eflags = ((int[])hougeki.api_at_eflag).Skip(1);\r
+ foreach (var turn in\r
+ targets.Zip(damages, (t, d) => new {t, d}).\r
+ Zip(eflags, (td, e) => new {e, td.t, td.d}))\r
+ {\r
+ foreach (var hit in turn.t.Zip(turn.d, (t, d) => new {t, d}))\r
+ {\r
+ if (turn.e == 1)\r
+ {\r
+ if (hit.t <= 6)\r
+ friend[hit.t - 1].ApplyDamage(hit.d);\r
+ else\r
+ guard[(hit.t - 1) % 6].ApplyDamage(hit.d);\r
+ }\r
+ else\r
+ {\r
+ if (hit.t <= 6)\r
+ enemy[hit.t - 1] -= hit.d;\r
+ else\r
+ enemyGuard[(hit.t - 1) % 6] -= hit.d;\r
+ }\r
+ }\r
+ }\r
}\r
\r
public void InspectBattleResult(dynamic json)\r
{\r
+ BattleState = BattleState.Result;\r
ShowResult();\r
CleanupResult();\r
+ SetEscapeShips(json);\r
}\r
\r
public void InspectPracticeResult(dynamic json)\r
{\r
+ BattleState = BattleState.Result;\r
ShowResult(false);\r
CleanupResult();\r
}\r
{\r
if (_friend == null)\r
return;\r
- var ships = _shipInfo.GetShipStatuses(_fleet);\r
- foreach (var e in ships.Zip(_friend, (ship, now) => new {ship, now}))\r
- e.now.UpdateShipStatus(e.ship);\r
+ var ships = _guard.Length > 0\r
+ ? _shipInfo.GetShipStatuses(0).Concat(_shipInfo.GetShipStatuses(1)).ToArray()\r
+ : _shipInfo.GetShipStatuses(_fleet);\r
+ foreach (var entry in ships.Zip(_friend.Concat(_guard), (ship, now) => new {ship, now}))\r
+ entry.now.UpdateShipStatus(entry.ship);\r
if (warnDamagedShip)\r
- UpdateDamgedShipNames(ships);\r
- }\r
-\r
- private void UpdateDamgedShipNames(IEnumerable<ShipStatus> ships)\r
- {\r
- DamagedShipNames =\r
- (from s in ships where s.DamageLevel == ShipStatus.Damage.Badly && !s.Escaped select s.Name).ToArray();\r
- HasDamagedShip = DamagedShipNames.Any();\r
+ _shipInfo.SetBadlyDamagedShips();\r
+ else\r
+ _shipInfo.ClearBadlyDamagedShips();\r
+ SetEnemyResultStatus();\r
}\r
\r
- public void InspectCombinedBattle(dynamic json, bool surfaceFleet)\r
+ private void SetEnemyResultStatus()\r
{\r
- InBattle = true;\r
- Formation = FormationName(json);\r
- EnemyFighterPower = CalcEnemyFighterPower(json);\r
- AirControlLevel = CheckAirControlLevel(json);\r
- _fleet = 10;\r
- ShowResultCombined(false);\r
- SetupResult(json);\r
- if (IsNightBattle(json))\r
- CalcHougekiDamage(json.api_hougeki, _guard, _enemyHp);\r
- else\r
- CalcDamage(json, surfaceFleet);\r
- ClearOverKill(_enemyHp);\r
- ResultRank = CalcResultRank();\r
+ for (var i = 0; i < 6; i++)\r
+ {\r
+ EnemyResultStatus[i].MaxHp = _enemyStartHp[i];\r
+ EnemyResultStatus[i].NowHp = _enemyHp[i];\r
+ }\r
+ for (var i = 6; i < EnemyResultStatus.Length; i++)\r
+ {\r
+ EnemyResultStatus[i].MaxHp = _enemyGuardStartHp[i - 6];\r
+ EnemyResultStatus[i].NowHp = _enemyGuardHp[i - 6];\r
+ }\r
}\r
\r
- public void InspectCombinedBattleResult(dynamic json)\r
+ public void SetEscapeShips(dynamic json)\r
{\r
_escapingShips.Clear();\r
- ShowResultCombined();\r
- CleanupResult();\r
- if ((int)json.api_escape_flag == 0)\r
+ if (!json.api_escape_flag() || (int)json.api_escape_flag == 0)\r
return;\r
var damaged = (int)json.api_escape.api_escape_idx[0] - 1;\r
_escapingShips.Add(_shipInfo.GetDeck(damaged / 6)[damaged % 6]);\r
_escapingShips.Add(_shipInfo.GetDeck(escort / 6)[escort % 6]);\r
}\r
\r
- private void ShowResultCombined(bool warnDamagedShip = true)\r
- {\r
- if (_friend == null)\r
- return;\r
- var ships = _shipInfo.GetShipStatuses(0).Concat(_shipInfo.GetShipStatuses(1)).ToArray();\r
- foreach (var e in ships.Zip(_friend.Concat(_guard), (ship, now) => new {ship, now}))\r
- e.now.UpdateShipStatus(e.ship);\r
- if (warnDamagedShip)\r
- UpdateDamgedShipNames(ships);\r
- }\r
-\r
public void CauseCombinedBattleEscape()\r
{\r
_shipInfo.SetEscapedShips(_escapingShips);\r
- UpdateDamgedShipNames(_shipInfo.GetShipStatuses(0).Concat(_shipInfo.GetShipStatuses(1)));\r
+ _shipInfo.SetBadlyDamagedShips();\r
}\r
\r
private class Record\r
{\r
- private ItemInfo _itemInfo;\r
- private int _maxHp;\r
- private int[] _slot;\r
- private int _slotEx;\r
- public int NowHp;\r
+ private ShipStatus _status;\r
+ public int NowHp => _status.NowHp;\r
+ public bool Escaped => _status.Escaped;\r
+ public ShipStatus.Damage DamageLevel => _status.DamageLevel;\r
public int StartHp;\r
- public int Damage;\r
\r
- public static Record[] Setup(int[] rawHp, int[] rawMax, int[][] slots, int[] slotEx, ItemInfo itemInfo)\r
- {\r
- var hp = rawHp.Skip(1).Take(6).TakeWhile(h => h != -1).ToArray();\r
- var max = rawMax.Skip(1).Take(6).TakeWhile(h => h != -1).ToArray();\r
- var r = new Record[hp.Length];\r
- for (var i = 0; i < hp.Length; i++)\r
- {\r
- r[i] = new Record\r
- {\r
- NowHp = hp[i],\r
- StartHp = hp[i],\r
- _maxHp = max[i],\r
- _slot = slots[i].ToArray(),\r
- _slotEx = slotEx[i],\r
- _itemInfo = itemInfo\r
- };\r
- }\r
- return r;\r
- }\r
+ public static Record[] Setup(ShipStatus[] ships) =>\r
+ (from s in ships select new Record {_status = (ShipStatus)s.Clone(), StartHp = s.NowHp}).ToArray();\r
\r
public void ApplyDamage(int damage)\r
{\r
- if (NowHp > damage)\r
- {\r
- NowHp -= damage;\r
- Damage += damage;\r
- return;\r
- }\r
- Damage += NowHp;\r
- NowHp = 0;\r
- var idex = _slotEx == 0 ? -1 : _itemInfo[_slotEx].Id;\r
- if (idex == 42) // ダメコン\r
+ if (_status.NowHp > damage)\r
{\r
- _slotEx = -1;\r
- NowHp = (int)(_maxHp * 0.2);\r
+ _status.NowHp -= damage;\r
return;\r
}\r
- if (idex == 43) // 女神\r
+ _status.NowHp = 0;\r
+ foreach (var item in new[] {_status.SlotEx}.Concat(_status.Slot))\r
{\r
- _slotEx = -1;\r
- NowHp = _maxHp;\r
- return;\r
- }\r
- for (var j = 0; j < _slot.Length; j++)\r
- {\r
- var id = _itemInfo[_slot[j]].Id;\r
- if (id == 42) // ダメコン\r
+ if (item.Spec.Id == 42)\r
{\r
- _slot[j] = -1;\r
- NowHp = (int)(_maxHp * 0.2);\r
+ _status.NowHp = (int)(_status.MaxHp * 0.2);\r
+ ConsumeSlotItem(_status, 42);\r
break;\r
}\r
- if (id == 43) // 女神\r
+ if (item.Spec.Id == 43)\r
{\r
- _slot[j] = -1;\r
- NowHp = _maxHp;\r
+ _status.NowHp = _status.MaxHp;\r
+ ConsumeSlotItem(_status, 43);\r
break;\r
}\r
}\r
public void UpdateShipStatus(ShipStatus ship)\r
{\r
ship.NowHp = NowHp;\r
- ship.Slot = _slot;\r
- ship.SlotEx = _slotEx;\r
+ ship.Slot = _status.Slot;\r
+ ship.SlotEx = _status.SlotEx;\r
}\r
}\r
\r
- // 以下のコードは航海日誌拡張版の以下のファイルのcalcResultRankを移植したもの\r
- // https://github.com/nekopanda/logbook/blob/94ceca4be6d4ce79a8759d1ee747fb9827c08edc/main/logbook/dto/BattleExDto.java\r
- //\r
- // The MIT License (MIT)\r
- //\r
- // Copyright (c) 2014-2015 航海日誌拡張版開発者\r
- //\r
- // Permission is hereby granted, free of charge, to any person obtaining a copy\r
- // of this software and associated documentation files (the "Software"), to deal\r
- // in the Software without restriction, including without limitation the rights\r
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
- // copies of the Software, and to permit persons to whom the Software is\r
- // furnished to do so, subject to the following conditions:\r
- //\r
- // The above copyright notice and this permission notice shall be included in\r
- // all copies or substantial portions of the Software.\r
- //\r
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
- // THE SOFTWARE.\r
- //\r
- private BattleResultRank CalcResultRank()\r
+ private BattleResultRank CalcLdAirBattleRank()\r
{\r
var combined = _friend.Concat(_guard).ToArray();\r
- // 戦闘後に残っている艦数\r
var friendNowShips = combined.Count(r => r.NowHp > 0);\r
- var enemyNowShips = _enemyHp.Count(hp => hp > 0);\r
- // 総ダメージ\r
- var friendGauge = combined.Sum(r => r.Damage);\r
- var enemyGauge = _enemyStartHp.Sum() - _enemyHp.Sum();\r
- // 轟沈・撃沈数\r
+ var friendGauge = combined.Sum(r => r.StartHp - r.NowHp);\r
var friendSunk = combined.Count(r => r.NowHp == 0);\r
- var enemySunk = _enemyHp.Count(hp => hp == 0);\r
-\r
var friendGaugeRate = Floor((double)friendGauge / combined.Sum(r => r.StartHp) * 100);\r
- var enemyGaugeRate = Floor((double)enemyGauge / _enemyStartHp.Sum() * 100);\r
- var equalOrMore = enemyGaugeRate > (0.9 * friendGaugeRate);\r
- var superior = enemyGaugeRate > 0 && enemyGaugeRate > (2.5 * friendGaugeRate);\r
\r
if (friendSunk == 0)\r
{\r
- if (enemyNowShips == 0)\r
- {\r
- if (friendGauge == 0)\r
- return BattleResultRank.P;\r
- return BattleResultRank.S;\r
- }\r
- if (_enemyHp.Length == 6)\r
- {\r
- if (enemySunk >= 4)\r
- return BattleResultRank.A;\r
- }\r
- else if (enemySunk * 2 >= _enemyHp.Length)\r
- {\r
+ if (friendGauge == 0)\r
+ return BattleResultRank.P;\r
+ if (friendGaugeRate < 10)\r
return BattleResultRank.A;\r
- }\r
- if (_enemyHp[0] == 0)\r
- return BattleResultRank.B;\r
- if (superior)\r
+ if (friendGaugeRate < 20)\r
return BattleResultRank.B;\r
+ if (friendGaugeRate < 50)\r
+ return BattleResultRank.C;\r
+ return BattleResultRank.D;\r
}\r
- else\r
+ if (friendSunk < friendNowShips)\r
+ return BattleResultRank.D;\r
+ return BattleResultRank.E;\r
+ }\r
+\r
+ private BattleResultRank CalcResultRank()\r
+ {\r
+ var friend = _friend.Concat(_guard).ToArray();\r
+ var enemyHp = _enemyHp.Concat(_enemyGuardHp).ToArray();\r
+ var enemyStartHp = _enemyStartHp.Concat(_enemyGuardStartHp).ToArray();\r
+\r
+ var friendCount = friend.Length;\r
+ var friendStartHpTotal = 0;\r
+ var friendNowHpTotal = 0;\r
+ var friendSunk = 0;\r
+ foreach (var ship in friend)\r
{\r
- if (enemyNowShips == 0)\r
- return BattleResultRank.B;\r
- if (_enemyHp[0] == 0 && friendSunk < enemySunk)\r
- return BattleResultRank.B;\r
- if (superior)\r
- return BattleResultRank.B;\r
- if (_enemyHp[0] == 0)\r
- return BattleResultRank.C;\r
+ if (ship.Escaped)\r
+ continue;\r
+ friendStartHpTotal += ship.StartHp;\r
+ friendNowHpTotal += ship.NowHp;\r
+ if (ship.NowHp == 0)\r
+ friendSunk++;\r
+ }\r
+ var friendGaugeRate = (int)((double)(friendStartHpTotal - friendNowHpTotal) / friendStartHpTotal * 100);\r
+\r
+ var enemyCount = enemyHp.Length;\r
+ var enemyStartHpTotal = enemyStartHp.Sum();\r
+ var enemyNowHpTotal = enemyHp.Sum();\r
+ var enemySunk = enemyHp.Count(hp => hp == 0);\r
+ var enemyGaugeRate = (int)((double)(enemyStartHpTotal - enemyNowHpTotal) / enemyStartHpTotal * 100);\r
+\r
+ if (friendSunk == 0 && enemySunk == enemyCount)\r
+ {\r
+ if (friendNowHpTotal >= friendStartHpTotal)\r
+ return BattleResultRank.P;\r
+ return BattleResultRank.S;\r
}\r
- if (enemyGauge > 0 && equalOrMore)\r
+ if (friendSunk == 0 && enemySunk >= (int)(enemyCount * 0.7) && enemyCount > 1)\r
+ return BattleResultRank.A;\r
+ if (friendSunk < enemySunk && enemyHp[0] == 0)\r
+ return BattleResultRank.B;\r
+ if (friendCount == 1 && friend[0].DamageLevel == ShipStatus.Damage.Badly)\r
+ return BattleResultRank.D;\r
+ if (enemyGaugeRate > friendGaugeRate * 2.5)\r
+ return BattleResultRank.B;\r
+ if (enemyGaugeRate > friendGaugeRate * 0.9)\r
return BattleResultRank.C;\r
- if (friendSunk > 0 && friendNowShips == 1)\r
+ if (friendCount > 1 && friendCount - 1 == friendSunk)\r
return BattleResultRank.E;\r
return BattleResultRank.D;\r
}\r