OSDN Git Service

報告書の「マス」を「経路」に直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Log / BattleLogger.cs
1 // Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.Collections.Generic;\r
17 using System.Linq;\r
18 using KancolleSniffer.Model;\r
19 \r
20 namespace KancolleSniffer.Log\r
21 {\r
22     public class BattleLogger\r
23     {\r
24         private readonly ItemInfo _itemInfo;\r
25         private readonly BattleInfo _battleInfo;\r
26         private readonly Action<string, string, string> _writer;\r
27         private readonly Dictionary<int, string> _mapName = new Dictionary<int, string>();\r
28         private readonly CellData _cell = new CellData();\r
29 \r
30         public BattleLogger(ItemInfo itemInfo, BattleInfo battleInfo, Action<string, string, string> writer)\r
31         {\r
32             _itemInfo = itemInfo;\r
33             _battleInfo = battleInfo;\r
34             _writer = writer;\r
35         }\r
36 \r
37         public void InspectMapInfoMaster(dynamic json)\r
38         {\r
39             foreach (var entry in json)\r
40                 _mapName[(int)entry.api_id] = entry.api_name;\r
41         }\r
42 \r
43         private class CellData\r
44         {\r
45             public bool Start;\r
46             public bool Boss;\r
47             public int Id;\r
48             public int Area;\r
49             public int Map;\r
50             public int Cell;\r
51 \r
52             public void Set(dynamic json)\r
53             {\r
54                 Area = (int)json.api_maparea_id;\r
55                 Map = (int)json.api_mapinfo_no;\r
56                 Cell = json.api_no() ? (int)json.api_no : 0;\r
57                 Boss = (int)json.api_event_id == 5;\r
58                 Id = Area * 10 + Map;\r
59             }\r
60         }\r
61 \r
62         public void InspectMapStart(dynamic json)\r
63         {\r
64             _cell.Start = true;\r
65             _cell.Set(json);\r
66         }\r
67 \r
68         public void InspectMapNext(dynamic json)\r
69         {\r
70             _cell.Set(json);\r
71             if (!json.api_destruction_battle())\r
72                 return;\r
73             WriteLog(null);\r
74             _cell.Start = false;\r
75         }\r
76 \r
77         public void InspectBattleResult(dynamic result)\r
78         {\r
79             WriteLog(result);\r
80             _cell.Start = false;\r
81         }\r
82 \r
83         private void WriteLog(dynamic result)\r
84         {\r
85             var log = CreateLog(result);\r
86             _writer("海戦・ドロップ報告書", log,\r
87                 "日付,海域,経路,ボス,ランク,艦隊行動,味方陣形,敵陣形,敵艦隊,ドロップ艦種,ドロップ艦娘," +\r
88                 "味方艦1,味方艦1HP,味方艦2,味方艦2HP,味方艦3,味方艦3HP,味方艦4,味方艦4HP,味方艦5,味方艦5HP,味方艦6,味方艦6HP," +\r
89                 "敵艦1,敵艦1HP,敵艦2,敵艦2HP,敵艦3,敵艦3HP,敵艦4,敵艦4HP,敵艦5,敵艦5HP,敵艦6,敵艦6HP," +\r
90                 "味方制空値,敵制空値,制空状態,マップ"\r
91             );\r
92         }\r
93 \r
94         private string CreateLog(dynamic result)\r
95         {\r
96             var fShips = GenerateShipList(_battleInfo.Result.Friend, s => $"{s.Name}(Lv{s.Level})");\r
97             var eShips = GenerateShipList(_battleInfo.Result.Enemy, s => $"{s.Name}");\r
98             var boss = "";\r
99             if (_cell.Start)\r
100                 boss = "出撃";\r
101             if (_battleInfo.BattleState != BattleState.AirRaid)\r
102             {\r
103                 if (_cell.Boss)\r
104                     boss = _cell.Start ? "出撃&ボス" : "ボス";\r
105             }\r
106             var dropType = CreateDropType(result);\r
107             var dropName = CreateDropName(result);\r
108             var enemyName = result?.api_enemy_info.api_deck_name ?? "";\r
109             var rank = result?.api_win_rank ?? _battleInfo.ResultRank;\r
110             var fp = _battleInfo.FighterPower;\r
111             var fPower = fp.Diff ? fp.RangeString : fp.Min.ToString();\r
112             return string.Join(",",\r
113                 _mapName[_cell.Id],\r
114                 _cell.Cell, boss,\r
115                 rank,\r
116                 BattleFormationName(_battleInfo.Formation[2]),\r
117                 FormationName(_battleInfo.Formation[0]),\r
118                 FormationName(_battleInfo.Formation[1]),\r
119                 enemyName,\r
120                 dropType, dropName,\r
121                 string.Join(",", fShips),\r
122                 string.Join(",", eShips),\r
123                 fPower, _battleInfo.EnemyFighterPower.AirCombat + _battleInfo.EnemyFighterPower.UnknownMark,\r
124                 AirControlLevelName(_battleInfo.AirControlLevel),\r
125                 $"{_cell.Area}-{_cell.Map}");\r
126         }\r
127 \r
128         private static string CreateDropType(dynamic result)\r
129         {\r
130             if (result == null)\r
131                 return "";\r
132             var type = result.api_get_ship() ? (string)result.api_get_ship.api_ship_type : "";\r
133             if (!result.api_get_useitem())\r
134                 return type;\r
135             return type == "" ? "アイテム" : type + "+アイテム";\r
136         }\r
137 \r
138         private string CreateDropName(dynamic result)\r
139         {\r
140             if (result == null)\r
141                 return "";\r
142             var name = result.api_get_ship() ? (string)result.api_get_ship.api_ship_name : "";\r
143             if (!result.api_get_useitem())\r
144                 return name;\r
145             var itemName = _itemInfo.GetUseItemName((int)result.api_get_useitem.api_useitem_id);\r
146             return name == "" ? itemName : name + "+" + itemName;\r
147         }\r
148 \r
149         private static IEnumerable<string> GenerateShipList(BattleInfo.BattleResult.Combined fleet,\r
150             Func<ShipStatus, string> toName)\r
151         {\r
152             fleet = FillEmpty(fleet);\r
153             if (fleet.Guard.Length > 0)\r
154             {\r
155                 return fleet.Main.Zip(fleet.Guard, (main, guard) =>\r
156                 {\r
157                     if (main.Empty && guard.Empty)\r
158                         return ",";\r
159                     var name = "";\r
160                     var hp = "";\r
161                     if (!main.Empty)\r
162                     {\r
163                         name = toName(main);\r
164                         hp = $"{main.NowHp}/{main.MaxHp}";\r
165                     }\r
166                     name += "・";\r
167                     hp += "・";\r
168                     if (!guard.Empty)\r
169                     {\r
170                         name += toName(guard);\r
171                         hp += $"{guard.NowHp}/{guard.MaxHp}";\r
172                     }\r
173                     return name + "," + hp;\r
174                 }).ToList();\r
175             }\r
176             var ships = fleet.Main;\r
177             if (fleet.Main.Length > 6)\r
178             {\r
179                 var result = new List<string>();\r
180                 for (var i = 0; i < 12 - ships.Length; i++)\r
181                 {\r
182                     var ship = fleet.Main[i];\r
183                     result.Add($"{toName(ship)},{ship.NowHp}/{ship.MaxHp}");\r
184                 }\r
185                 for (var i = 0; i < ships.Length - 6; i++)\r
186                 {\r
187                     var s1 = ships[12 - ships.Length + i];\r
188                     var s2 = ships[6 + i];\r
189                     result.Add(\r
190                         $"{toName(s1)}・{toName(s2)}," +\r
191                         $"{s1.NowHp}/{s1.MaxHp}・{s2.NowHp}/{s2.MaxHp}");\r
192                 }\r
193                 return result;\r
194             }\r
195             return ships.Select(ship => ship.Empty ? "," : $"{toName(ship)},{ship.NowHp}/{ship.MaxHp}");\r
196         }\r
197 \r
198         private static BattleInfo.BattleResult.Combined FillEmpty(BattleInfo.BattleResult.Combined fleet)\r
199         {\r
200             return new BattleInfo.BattleResult.Combined\r
201             {\r
202                 Main = FillEmpty(fleet.Main),\r
203                 Guard = FillEmpty(fleet.Guard)\r
204             };\r
205         }\r
206 \r
207         private static readonly ShipStatus[] Padding =\r
208             Enumerable.Repeat(new ShipStatus(), ShipInfo.MemberCount).ToArray();\r
209 \r
210         private static ShipStatus[] FillEmpty(ShipStatus[] ships)\r
211         {\r
212             return ships.Length > ShipInfo.MemberCount || ships.Length == 0\r
213                 ? ships\r
214                 : ships.Concat(Padding).Take(ShipInfo.MemberCount).ToArray();\r
215         }\r
216 \r
217         private string FormationName(dynamic f)\r
218         {\r
219             if (f is string) // 連合艦隊のときは文字列\r
220                 f = int.Parse(f);\r
221             switch ((int)f)\r
222             {\r
223                 case 1:\r
224                     return "単縦陣";\r
225                 case 2:\r
226                     return "複縦陣";\r
227                 case 3:\r
228                     return "輪形陣";\r
229                 case 4:\r
230                     return "梯形陣";\r
231                 case 5:\r
232                     return "単横陣";\r
233                 case 6:\r
234                     return "警戒陣";\r
235                 case 11:\r
236                     return "第一警戒航行序列";\r
237                 case 12:\r
238                     return "第二警戒航行序列";\r
239                 case 13:\r
240                     return "第三警戒航行序列";\r
241                 case 14:\r
242                     return "第四警戒航行序列";\r
243                 default:\r
244                     return "単縦陣";\r
245             }\r
246         }\r
247 \r
248         private static string BattleFormationName(int f)\r
249         {\r
250             switch (f)\r
251             {\r
252                 case 1:\r
253                     return "同航戦";\r
254                 case 2:\r
255                     return "反航戦";\r
256                 case 3:\r
257                     return "T字戦(有利)";\r
258                 case 4:\r
259                     return "T字戦(不利)";\r
260                 default:\r
261                     return "同航戦";\r
262             }\r
263         }\r
264 \r
265         private string AirControlLevelName(int level)\r
266         {\r
267             switch (level)\r
268             {\r
269                 case 0:\r
270                     return "航空均衡";\r
271                 case 1:\r
272                     return "制空権確保";\r
273                 case 2:\r
274                     return "航空優勢";\r
275                 case 3:\r
276                     return "航空劣勢";\r
277                 case 4:\r
278                     return "制空権喪失";\r
279                 default:\r
280                     return "";\r
281             }\r
282         }\r
283     }\r
284 }