OSDN Git Service

Doutakuを導入
[kcd/KCD.git] / KCD / CalculateDamageCommand.swift
1 //
2 //  CalculateDamageCommand.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/01/15.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10 import SwiftyJSON
11
12 enum BattleType {
13     
14     case normal
15     case combinedAir
16     case combinedWater
17     case eachCombinedAir
18     case eachCombinedWater
19     case enemyCombined
20 }
21
22 enum DamageControlID: Int {
23     
24     case damageControl = 42
25     case goddes = 43
26 }
27
28 final class CalculateDamageCommand: JSONCommand {
29     
30     override func execute() {
31         
32         switch api.endpoint {
33             
34         case .battle, .airBattle, .ldAirBattle:
35             normalBattle(battleType: .normal)
36             
37         case .combinedEcBattle:
38             enemyCombinedBattle(battleType: .enemyCombined)
39             
40         case .combinedBattle, .combinedAirBattle:
41             combinedAirBattle(battleType: .combinedAir)
42             
43         case .combinedBattleWater, .combinedLdAirBattle:
44             normalBattle(battleType: .combinedWater)
45             
46         case .combinedEachBattle:
47             eachAirBattle(battleType: .eachCombinedAir)
48             
49         case .combinedEachBattleWater:
50             normalBattle(battleType: .eachCombinedWater)
51             
52         case .combinedEachNightToDay:
53             eachNightToDayBattle(battleType: .normal)
54             
55         case .midnightBattle, .midnightSpMidnight:
56             midnightBattle(battleType: .normal)
57             
58         case .combinedMidnightBattle, .combinedSpMidnight:
59             midnightBattle(battleType: .combinedAir)
60             
61         case .combinedEcMidnightBattle:
62             midnightBattle(battleType: .eachCombinedAir)
63             
64         case .battleResult, .combinedBattleResult:
65             applyDamage()
66             resetDamage()
67             
68         default: return Logger.shared.log("Missing API: \(apiResponse.api)")
69         }
70     }
71     
72     func normalBattle(battleType: BattleType) {
73         
74         updateBattleCell()
75         DamageCalculator(json, battleType).calculateBattle()
76     }
77     
78     func combinedAirBattle(battleType: BattleType) {
79         
80         updateBattleCell()
81         DamageCalculator(json, battleType).calcCombinedBattleAir()
82     }
83     
84     func eachAirBattle(battleType: BattleType) {
85         
86         updateBattleCell()
87         DamageCalculator(json, battleType).calcEachBattleAir()
88     }
89     
90     func eachNightToDayBattle(battleType: BattleType) {
91         
92         updateBattleCell()
93         DamageCalculator(json, battleType).calcEachNightToDay()
94     }
95     
96     func enemyCombinedBattle(battleType: BattleType) {
97         
98         updateBattleCell()
99         DamageCalculator(json, battleType).calcEnemyCombinedBattle()
100     }
101     
102     func midnightBattle(battleType: BattleType) {
103         
104         DamageCalculator(json, battleType).calcMidnight()
105     }
106 }
107
108 extension CalculateDamageCommand {
109     
110     func resetDamage() {
111         
112         let store = TemporaryDataStore.oneTimeEditor()
113         
114         store.sync { store.damages().forEach(store.delete) }
115     }
116     
117     func applyDamage() {
118         
119         let store = TemporaryDataStore.oneTimeEditor()
120         
121         let totalDamages = store.sync { store.sortedDamagesById() }
122         
123         let aStore = ServerDataStore.default
124         
125         Debug.excute(level: .debug) {
126             
127             print("-------")
128             
129             store.sync {
130                 totalDamages.forEach { damage in
131                     
132                     let shipId = damage.shipID
133                     guard let ship = aStore.sync(execute: { aStore.ship(by: shipId) }) else { return }
134                     
135                     let damagedHp = damage.hp
136                     aStore.sync {
137                         if ship.nowhp != damagedHp {
138                             
139                             print("\(ship.name)(\(ship.id)),HP \(ship.nowhp) -> \(damagedHp)")
140                         }
141                     }
142                 }
143             }
144             
145             print("------- End Battle")
146         }
147         
148         // 第二艦隊単独出撃で正しくデータが反映されるように逆順にして計算
149         store.sync {
150             totalDamages.reversed().forEach { damage in
151                 
152                 let shipId = damage.shipID
153                 guard let ship = aStore.sync(execute: { aStore.ship(by: shipId) }) else { return }
154                 
155                 let damagedHp = damage.hp
156                 aStore.sync { ship.nowhp = damagedHp }
157                 
158                 if damage.useDamageControl { self.removeFirstDamageControl(of: shipId) }
159             }
160         }
161     }
162     
163     func updateBattleCell() {
164         
165         let store = TemporaryDataStore.default
166         
167         guard let battle = store.sync(execute: { store.battle() }) else {
168             
169             return Logger.shared.log("Battle is invalid.")
170         }
171         
172         store.sync { battle.battleCell = (battle.no == 0 ? nil : battle.no as NSNumber) }
173         
174         Debug.excute(level: .debug) {
175             
176             print("Enter Cell ------- ")
177             
178             if let seiku = json["api_data"]["api_kouku"]["api_stage1"]["api_disp_seiku"].int {
179                 
180                 switch seiku {
181                 case 0: print("制空権 均衡")
182                 case 1: print("制空権 確保")
183                 case 2: print("制空権 優勢")
184                 case 3: print("制空権 劣勢")
185                 case 4: print("制空権 喪失")
186                 default: break
187                 }
188             }
189             
190             if let intercept = json["api_data"]["api_formation"][2].int {
191                 
192                 switch intercept {
193                 case 1: print("交戦形態 同航戦")
194                 case 2: print("交戦形態 反航戦")
195                 case 3: print("交戦形態 T字戦有利")
196                 case 4: print("交戦形態 T字戦不利")
197                 default: break
198                 }
199             }
200         }
201     }
202     
203     func removeFirstDamageControl(of shipId: Int) {
204         
205         let store = ServerDataStore.oneTimeEditor()
206         store.sync {
207             
208             guard let ship = store.ship(by: shipId) else { return }
209             
210             let (item, damageControl) = ship
211                 .equippedItem
212                 .lazy
213                 .compactMap { $0 as? SlotItem }
214                 .map { ($0, store.masterSlotItemID(by: $0.id)) }
215                 .map { ($0.0, DamageControlID(rawValue: $0.1)) }
216                 .filter { $0.1 != nil }
217                 .first ?? (nil, nil)
218             
219             if let validDamageControl = damageControl {
220                 
221                 switch validDamageControl {
222                 case .damageControl: break
223                     
224                 case .goddes:
225                     ship.fuel = ship.maxFuel
226                     ship.bull = ship.maxBull
227                 }
228                 
229                 guard let equiped = ship.equippedItem.array as? [SlotItem] else { return }
230                 
231                 ship.equippedItem = NSOrderedSet(array: equiped.filter { $0 != item })
232                 
233                 return
234             }
235             
236             // check extra slot
237             let exItemId = store.sync { store.masterSlotItemID(by: ship.slot_ex) }
238             
239             guard let exType = DamageControlID(rawValue: exItemId) else { return }
240             
241             switch exType {
242             case .damageControl: break
243                 
244             case .goddes:
245                 ship.fuel = ship.maxFuel
246                 ship.bull = ship.maxBull
247             }
248             
249             ship.slot_ex = -1
250         }
251     }
252 }