OSDN Git Service

ダメージ計算部分を別クラスに変更
authormasakih <masakih@users.sourceforge.jp>
Sun, 23 Jul 2017 10:47:21 +0000 (19:47 +0900)
committermasakih <masakih@users.sourceforge.jp>
Sun, 23 Jul 2017 10:47:21 +0000 (19:47 +0900)
KCD/CalculateDamageCommand.swift
KCD/DamageCalculator.swift

index 3c21826..673dd3f 100644 (file)
@@ -10,6 +10,7 @@ import Cocoa
 import SwiftyJSON
 
 enum BattleType {
+    
     case normal
     case combinedAir
     case combinedWater
@@ -17,141 +18,136 @@ enum BattleType {
     case eachCombinedWater
     case enemyCombined
 }
+
 enum DamageControlID: Int {
+    
     case damageControl = 42
     case goddes = 43
 }
-enum BattleFleet {
-    case first
-    case second
-    case each
-}
 
-class CalculateDamageCommand: JSONCommand {
-    private let store = TemporaryDataStore.oneTimeEditor()
-    
-    var battleType: BattleType = .normal
-    var damages: [Damage] {
-        let array = store.sortedDamagesById()
-        if array.count != 12 {
-            buildDamagedEntity()
-            let newDamages = store.sortedDamagesById()
-            guard newDamages.count == 12
-                else {
-                    print("ERROR!!!! CAN NOT CREATE DAMAGE OBJECT")
-                    return []
-            }
-            return newDamages
-        }
-        return array
-    }
-    var isCombinedBattle: Bool {
-        switch battleType {
-        case .combinedAir, .combinedWater, .eachCombinedAir, .eachCombinedWater:
-            return true
-        default:
-            return false
-        }
-    }
+final class CalculateDamageCommand: JSONCommand {
     
     override func execute() {
+        
         guard let battleApi = BattleAPI(rawValue: api)
             else { return }
         
         switch battleApi {
         case .battle, .airBattle, .ldAirBattle:
-            calculateBattle()
+            normalBattle(battleType: .normal)
+            
         case .combinedEcBattle:
-            battleType = .enemyCombined
-            calcEnemyCombinedBattle()
+            enemyCombinedBattle(battleType: .enemyCombined)
+            
         case .combinedBattle, .combinedAirBattle:
-            battleType = .combinedAir
-            calcCombinedBattleAir()
+            combinedAirBattle(battleType: .combinedAir)
+            
         case .combinedBattleWater, .combinedLdAirBattle:
-            battleType = .combinedWater
-            calculateBattle()
+            normalBattle(battleType: .combinedWater)
+            
         case .combinedEachBattle:
-            battleType = .eachCombinedAir
-            calcEachBattleAir()
+            eachAirBattle(battleType: .eachCombinedAir)
+            
         case .combinedEachBattleWater:
-            battleType = .eachCombinedWater
-            calculateBattle()
+            normalBattle(battleType: .eachCombinedWater)
+            
         case .midnightBattle, .midnightSpMidnight:
-            calcMidnight()
+            midnightBattle(battleType: .normal)
+            
         case .combinedMidnightBattle, .combinedSpMidnight:
-            battleType = .combinedAir
-            calcMidnight()
+            midnightBattle(battleType: .combinedAir)
+            
         case .combinedEcMidnightBattle:
-            battleType = .eachCombinedAir
-            calcMidnight()
+            midnightBattle(battleType: .eachCombinedAir)
+            
         case .battleResult, .combinedBattleResult:
             applyDamage()
             resetDamage()
         }
     }
     
-    private func resetDamage() {
+    func normalBattle(battleType: BattleType) {
+        
+        updateBattleCell()
+        DamageCalculator(json, battleType).calculateBattle()
+    }
+    
+    func combinedAirBattle(battleType: BattleType) {
+        
+        updateBattleCell()
+        DamageCalculator(json, battleType).calcCombinedBattleAir()
+    }
+    
+    func eachAirBattle(battleType: BattleType) {
+        
+        updateBattleCell()
+        DamageCalculator(json, battleType).calcEachBattleAir()
+    }
+    
+    func enemyCombinedBattle(battleType: BattleType) {
+        
+        DamageCalculator(json, battleType).calcEnemyCombinedBattle()
+    }
+    
+    func midnightBattle(battleType: BattleType) {
+        
+        DamageCalculator(json, battleType).calcMidnight()
+    }
+}
+
+extension CalculateDamageCommand {
+    
+    func resetDamage() {
+        
+        let store = TemporaryDataStore.oneTimeEditor()
+        
         store.damages().forEach { store.delete($0) }
     }
-    private func applyDamage() {
+    
+    func applyDamage() {
+        
+        let store = TemporaryDataStore.oneTimeEditor()
+        
         let totalDamages = store.sortedDamagesById()
+        
         guard totalDamages.count == 12
             else { return print("Damages count is invalid. count is \(totalDamages.count).") }
+        
         let aStore = ServerDataStore.oneTimeEditor()
+        
         totalDamages.forEach {
+            
             guard let ship = aStore.ship(by: $0.shipID)
                 else { return }
             
             if ship.nowhp != $0.hp {
+                
                 Debug.print("\(ship.name)(\(ship.id)),HP \(ship.nowhp) -> \($0.hp)", level: .debug)
             }
             
             ship.nowhp = $0.hp
+            
             if $0.useDamageControl { removeFirstDamageControl(of: ship) }
         }
         
         Debug.print("------- End Battle", level: .debug)
     }
-    private func buildDamagedEntity() {
-        guard let battle = store.battle()
-            else { return print("Battle is invalid.") }
-        
-        let aStore = ServerDataStore.default
-        var ships: [Any] = []
-        
-        // 第一艦隊
-        let firstFleetShips = aStore.ships(byDeckId: battle.deckId)
-        ships += (firstFleetShips as [Any])
-        while ships.count != 6 {
-            ships.append(0)
-        }
-        
-        // 第二艦隊
-        let secondFleetShips = aStore.ships(byDeckId: 2)
-        ships += (secondFleetShips as [Any])
-        while ships.count != 12 {
-            ships.append(0)
-        }
-        ships.enumerated().forEach {
-            guard let damage = store.createDamage()
-                else { return print("Can not create Damage") }
-            damage.battle = battle
-            damage.id = $0.offset
-            if let ship = $0.element as? Ship {
-                damage.hp = ship.nowhp
-                damage.shipID = ship.id
-            }
-        }
-    }
     
     func updateBattleCell() {
+        
+        let store = TemporaryDataStore.default
+        
         guard let battle = store.battle()
             else { return print("Battle is invalid.") }
+        
         battle.battleCell = (battle.no == 0 ? nil : battle.no as NSNumber)
         
         Debug.excute(level: .debug) {
+            
             print("Enter Cell ------- ")
+            
             if let seiku = json["api_data"]["api_kouku"]["api_stage1"]["api_disp_seiku"].int {
+                
                 switch seiku {
                 case 0: print("制空権 均衡")
                 case 1: print("制空権 確保")
@@ -161,7 +157,9 @@ class CalculateDamageCommand: JSONCommand {
                 default: break
                 }
             }
+            
             if let intercept = json["api_data"]["api_formation"][2].int {
+                
                 switch intercept {
                 case 1: print("交戦形態 同航戦")
                 case 2: print("交戦形態 反航戦")
@@ -172,4 +170,59 @@ class CalculateDamageCommand: JSONCommand {
             }
         }
     }
+    
+    func removeFirstDamageControl(of ship: Ship) {
+        
+        let equiped = ship.equippedItem
+        let newEquiped = equiped.array
+        let store = ServerDataStore.default
+        var useDamageControl = false
+        
+        equiped.forEach {
+            
+            if useDamageControl { return }
+            
+            guard let master = $0 as? SlotItem
+                else { return }
+            
+            let masterSlotItemId = store.masterSlotItemID(by: master.id)
+            
+            guard let type = DamageControlID(rawValue: masterSlotItemId)
+                else { return }
+            
+            switch type {
+            case .goddes:
+                ship.fuel = ship.maxFuel
+                ship.bull = ship.maxBull
+                fallthrough
+                
+            case .damageControl:
+                if var equiped = newEquiped as? [SlotItem],
+                    let index = equiped.index(of: master) {
+                    
+                    equiped[index...index] = []
+                    ship.equippedItem = NSOrderedSet(array: equiped)
+                    useDamageControl = true
+                }
+            }
+        }
+        
+        if useDamageControl { return }
+        
+        // check extra slot
+        let exItemId = store.masterSlotItemID(by: ship.slot_ex)
+        
+        guard let exType = DamageControlID(rawValue: exItemId)
+            else { return }
+        
+        switch exType {
+        case .goddes:
+            ship.fuel = ship.maxFuel
+            ship.bull = ship.maxBull
+            fallthrough
+            
+        case .damageControl:
+            ship.slot_ex = -1
+        }
+    }
 }
index f18a614..0d560d8 100644 (file)
 import Cocoa
 import SwiftyJSON
 
-// MARK: - Primitive Calclator
-extension CalculateDamageCommand {
-    private func hogekiTargets(_ list: JSON) -> [[Int]]? {
-        guard let targetArraysArray = list
-            .array?
-            .flatMap({ $0.array?.flatMap { $0.int } })
-            else { return nil }
-        guard list.count - 1 == targetArraysArray.count
-            else {
-                print("api_df_list is wrong")
-                return nil
-        }
-        return targetArraysArray
-    }
-    private func hogekiDamages(_ list: JSON) -> [[Int]]? {
-        return list.array?.flatMap { $0.array?.flatMap { $0.int } }
-    }
-    private func enemyFlags(_ list: JSON) -> [Int]? {
-        return list.array?.flatMap { $0.int }.filter { $0 != -1 }
-    }
-    private func isTargetFriend(eFlags: [Int]?, index: Int) -> Bool {
-        if let eFlags = eFlags, 0..<eFlags.count ~= index {
-            return eFlags[index] == 1
-        }
-        return true
-    }
-    private func validTargetPos(_ targetPos: Int, in battleFleet: BattleFleet) -> Bool {
-        let upper = (battleFleet == .each ? 12 : 6)
-        return 1...upper ~= targetPos
-    }
-    private func position(_ pos: Int, in fleet: BattleFleet) -> Int? {
-        let shipOffset = (fleet == .second) ? 6 : 0
-        let damagePos = pos - 1 + shipOffset
-        guard 0..<damages.count ~= damagePos
-            else { return nil }
-        return damagePos
-    }
-    private func calcHP(damage: Damage, receive: Int) {
-        let hp = damage.hp as Int
-        var newHP = hp - receive
-        if newHP <= 0 {
-            let shipId = damage.shipID
-            if let ship = ServerDataStore.default.ship(by: shipId) {
-                let efectiveHP = damageControlIfPossible(nowhp: newHP, ship: ship)
-                if efectiveHP != 0, efectiveHP != newHP {
-                    damage.useDamageControl = true
-                }
-                newHP = efectiveHP
-            }
-        }
-        damage.hp = newHP
-    }
-    fileprivate func calculateHogeki(baseKeyPath: String, _ bf: () -> BattleFleet) {
-        calculateHogeki(baseKeyPath: baseKeyPath, battleFleet: bf())
+enum BattleFleet {
+    
+    case first
+    case second
+    case each
+}
+
+final class DamageCalculator {
+    
+    fileprivate let store = TemporaryDataStore.oneTimeEditor()
+    
+    fileprivate let json: JSON
+    fileprivate let battleType: BattleType
+    
+    init(_ json: JSON, _ battleType: BattleType = .normal) {
+        
+        self.battleType = battleType
+        self.json = json
     }
-    fileprivate func calculateHogeki(baseKeyPath: String, battleFleet: BattleFleet = .first) {
-        let baseValue = json[baseKeyPath.components(separatedBy: ".")]
-        guard let targetPosLists = hogekiTargets(baseValue["api_df_list"]),
-            let damageLists = hogekiDamages(baseValue["api_damage"])
-            else { return }
-        guard targetPosLists.count == damageLists.count
-            else { return print("api_damage is wrong.") }
+}
+
+// MARK: - Battle type
+extension DamageCalculator {
+    
+    func calculateBattle() {
         
-        let eFlags = enemyFlags(baseValue["api_at_eflag"])
+        calcKouku()
+        calcOpeningTaisen()
+        calcOpeningAttack()
+        calcHougeki1()
+        calcHougeki2()
+        calcHougeki3()
+        calcRaigeki()
+    }
+    
+    func calcCombinedBattleAir() {
         
-        Debug.print("Start Hougeki \(baseKeyPath)", level: .debug)
-        zip(targetPosLists, damageLists).enumerated().forEach { (i, list) in
-            if !isTargetFriend(eFlags: eFlags, index: i) { return }
-            
-            zip(list.0, list.1).forEach { (targetPos, damage) in
-                guard validTargetPos(targetPos, in: battleFleet) else { return }
-                
-                guard let damagePos = position(targetPos, in: battleFleet)
-                    else { return print("damage pos is larger than damage count") }
-                calcHP(damage: damages[damagePos], receive: damage)
-                
-                Debug.excute(level: .debug) {
-                    let shipOffset = (battleFleet == .second) ? 6 : 0
-                    print("Hougeki \(targetPos + shipOffset) -> \(damage)")
-                }
-            }
-        }
+        calcKouku()
+        calcOpeningTaisen()
+        calcOpeningAttack()
+        calcHougeki1()
+        calcRaigeki()
+        calcHougeki2()
+        calcHougeki3()
     }
-    fileprivate func calculateFDam(baseKeyPath: String, _ bf: () -> BattleFleet) {
-        calculateFDam(baseKeyPath: baseKeyPath, battleFleet: bf())
+    
+    func calcEachBattleAir() {
+        
+        calcKouku()
+        calcOpeningTaisen()
+        calcOpeningAttack()
+        calcHougeki1()
+        calcHougeki2()
+        calcRaigeki()
+        calcHougeki3()
     }
-    fileprivate func calculateFDam(baseKeyPath: String, battleFleet: BattleFleet = .first) {
-        let baseValue = json[baseKeyPath.components(separatedBy: ".")]
-        guard let koukuDamages = baseValue["api_fdam"].arrayObject as? [Int]
-            else { return }
+    
+    func calcEnemyCombinedBattle() {
         
-        Debug.print("Start FDam \(baseKeyPath)", level: .debug)
+        // same phase as combined air
+        calcCombinedBattleAir()
+    }
+    
+    func calcMidnight() {
         
-        koukuDamages.enumerated().forEach { (idx, damage) in
-            if idx == 0 { return }
-            
-            guard let damagePos = position(idx, in: battleFleet)
-                else { return }
-            calcHP(damage: damages[damagePos], receive: damage)
-            
-            Debug.excute(level: .debug) {
-                let shipOffset = (battleFleet == .second) ? 6 : 0
-                print("FDam \(idx + shipOffset) -> \(damage)")
-            }
-        }
+        calculateMidnightBattle()
     }
 }
+
 // MARK: - Battle phase
-extension CalculateDamageCommand {
+extension DamageCalculator {
+    
     fileprivate func calcKouku() {
+        
         calculateFDam(baseKeyPath: "api_data.api_kouku.api_stage3")
         calculateFDam(baseKeyPath: "api_data.api_kouku2.api_stage3")
         
@@ -139,7 +103,9 @@ extension CalculateDamageCommand {
         calculateFDam(baseKeyPath: "api_data.api_kouku2.api_stage3_combined", bf)
         
     }
+    
     fileprivate func calcOpeningAttack() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第2
         // 連合vs通常(機動) 第2
@@ -153,12 +119,16 @@ extension CalculateDamageCommand {
             }
         }
     }
+    
     fileprivate func calcOpeningTaisen() {
+        
         calculateHogeki(baseKeyPath: "api_data.api_opening_taisen") {
             isCombinedBattle ? .second : .first
         }
     }
+    
     fileprivate func calcHougeki1() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第1
         // 連合vs通常(機動) 第2
@@ -171,7 +141,9 @@ extension CalculateDamageCommand {
             }
         }
     }
+    
     fileprivate func calcHougeki2() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第1
         // 連合vs通常(機動) 第1
@@ -180,12 +152,14 @@ extension CalculateDamageCommand {
         calculateHogeki(baseKeyPath: "api_data.api_hougeki2") {
             switch battleType {
             case .eachCombinedWater: return .each
-            //            case .eachCombinedAir: return .second  // 1~12
+//            case .eachCombinedAir: return .second  // 1~12
             default: return .first
             }
         }
     }
+    
     fileprivate func calcHougeki3() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第2
         // 連合vs通常(機動) 第1
@@ -194,13 +168,15 @@ extension CalculateDamageCommand {
         calculateHogeki(baseKeyPath: "api_data.api_hougeki3") {
             switch battleType {
             case .combinedWater: return .second
-            //            case .eachCombinedWater: return .second  // 1~12
+//            case .eachCombinedWater: return .second  // 1~12
             case .eachCombinedAir: return .each
             default: return .first
             }
         }
     }
+    
     fileprivate func calcRaigeki() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第2
         // 連合vs通常(機動) 第2
@@ -216,6 +192,7 @@ extension CalculateDamageCommand {
     }
     
     fileprivate func calculateMidnightBattle() {
+        
         // 艦隊 戦闘艦隊
         // 連合vs通常(水上) 第2
         // 連合vs通常(機動) 第2
@@ -226,122 +203,298 @@ extension CalculateDamageCommand {
         }
     }
 }
-// MARK: - Battle type
-extension CalculateDamageCommand {
-    func calculateBattle() {
-        updateBattleCell()
+
+// MARK: - Properties
+extension DamageCalculator {
+    
+    fileprivate var damages: [Damage] {
         
-        calcKouku()
-        calcOpeningTaisen()
-        calcOpeningAttack()
-        calcHougeki1()
-        calcHougeki2()
-        calcHougeki3()
-        calcRaigeki()
+        let array = store.sortedDamagesById()
+        
+        if array.count != 12 {
+            
+            buildDamagedEntity()
+            
+            let newDamages = store.sortedDamagesById()
+            
+            guard newDamages.count == 12
+                else {
+                    print("ERROR!!!! CAN NOT CREATE DAMAGE OBJECT")
+                    return []
+            }
+            
+            return newDamages
+        }
+        
+        return array
     }
-    func calcCombinedBattleAir() {
-        updateBattleCell()
+    
+    fileprivate var isCombinedBattle: Bool {
         
-        calcKouku()
-        calcOpeningTaisen()
-        calcOpeningAttack()
-        calcHougeki1()
-        calcRaigeki()
-        calcHougeki2()
-        calcHougeki3()
+        switch battleType {
+        case .combinedAir, .combinedWater, .eachCombinedAir, .eachCombinedWater:
+            return true
+            
+        default:
+            return false
+        }
     }
-    func calcEachBattleAir() {
-        updateBattleCell()
+    
+    fileprivate func buildDamagedEntity() {
         
-        calcKouku()
-        calcOpeningTaisen()
-        calcOpeningAttack()
-        calcHougeki1()
-        calcHougeki2()
-        calcRaigeki()
-        calcHougeki3()
+        guard let battle = store.battle()
+            else { return print("Battle is invalid.") }
+        
+        let aStore = ServerDataStore.default
+        var ships: [Any] = []
+        
+        // 第一艦隊
+        let firstFleetShips = aStore.ships(byDeckId: battle.deckId)
+        
+        ships += (firstFleetShips as [Any])
+        
+        while ships.count != 6 {
+            
+            ships.append(0)
+        }
+        
+        // 第二艦隊
+        let secondFleetShips = aStore.ships(byDeckId: 2)
+        
+        ships += (secondFleetShips as [Any])
+        
+        while ships.count != 12 {
+            
+            ships.append(0)
+        }
+        
+        ships.enumerated().forEach {
+            
+            guard let damage = store.createDamage()
+                else { return print("Can not create Damage") }
+            
+            damage.battle = battle
+            damage.id = $0.offset
+            
+            if let ship = $0.element as? Ship {
+                
+                damage.hp = ship.nowhp
+                damage.shipID = ship.id
+            }
+        }
     }
-    func calcEnemyCombinedBattle() {
-        // same phase as combined air
-        calcCombinedBattleAir()
+}
+
+// MARK: - Primitive Calclator
+extension DamageCalculator {
+    
+    private func hogekiTargets(_ list: JSON) -> [[Int]]? {
+        
+        guard let targetArraysArray = list
+            .array?
+            .flatMap({ $0.array?.flatMap { $0.int } })
+            else { return nil }
+        
+        guard list.count - 1 == targetArraysArray.count
+            else {
+                print("api_df_list is wrong")
+                return nil
+        }
+        
+        return targetArraysArray
     }
-    func calcMidnight() {
-        calculateMidnightBattle()
+    
+    private func hogekiDamages(_ list: JSON) -> [[Int]]? {
+        
+        return list.array?.flatMap { $0.array?.flatMap { $0.int } }
+    }
+    
+    private func enemyFlags(_ list: JSON) -> [Int]? {
+        
+        return list.array?.flatMap { $0.int }.filter { $0 != -1 }
+    }
+    
+    private func isTargetFriend(eFlags: [Int]?, index: Int) -> Bool {
+        
+        if let eFlags = eFlags, 0..<eFlags.count ~= index {
+            
+            return eFlags[index] == 1
+        }
+        
+        return true
+    }
+    
+    private func validTargetPos(_ targetPos: Int, in battleFleet: BattleFleet) -> Bool {
+        
+        let upper = (battleFleet == .each ? 12 : 6)
+        
+        return 1...upper ~= targetPos
+    }
+    
+    private func position(_ pos: Int, in fleet: BattleFleet) -> Int? {
+        
+        let shipOffset = (fleet == .second) ? 6 : 0
+        
+        let damagePos = pos - 1 + shipOffset
+        
+        guard case 0..<damages.count = damagePos
+            else { return nil }
+        
+        return damagePos
+    }
+    
+    private func calcHP(damage: Damage, receive: Int) {
+        
+        let hp = damage.hp as Int
+        
+        var newHP = hp - receive
+        
+        if newHP <= 0 {
+            
+            let shipId = damage.shipID
+            
+            if let ship = ServerDataStore.default.ship(by: shipId) {
+                
+                let efectiveHP = damageControlIfPossible(nowhp: newHP, ship: ship)
+                
+                if efectiveHP != 0, efectiveHP != newHP {
+                    
+                    damage.useDamageControl = true
+                }
+                
+                newHP = efectiveHP
+            }
+        }
+        
+        damage.hp = newHP
+    }
+    
+    fileprivate func calculateHogeki(baseKeyPath: String, _ bf: () -> BattleFleet) {
+        
+        calculateHogeki(baseKeyPath: baseKeyPath, battleFleet: bf())
+    }
+    
+    fileprivate func calculateHogeki(baseKeyPath: String, battleFleet: BattleFleet = .first) {
+        
+        let baseValue = json[baseKeyPath.components(separatedBy: ".")]
+        
+        guard let targetPosLists = hogekiTargets(baseValue["api_df_list"]),
+            let damageLists = hogekiDamages(baseValue["api_damage"])
+            else { return }
+        
+        guard targetPosLists.count == damageLists.count
+            else { return print("api_damage is wrong.") }
+        
+        let eFlags = enemyFlags(baseValue["api_at_eflag"])
+        
+        Debug.print("Start Hougeki \(baseKeyPath)", level: .debug)
+        
+        zip(targetPosLists, damageLists).enumerated().forEach { (i, list) in
+            
+            if !isTargetFriend(eFlags: eFlags, index: i) { return }
+            
+            zip(list.0, list.1).forEach { (targetPos, damage) in
+                
+                guard validTargetPos(targetPos, in: battleFleet)
+                    else { return }
+                
+                guard let damagePos = position(targetPos, in: battleFleet)
+                    else { return print("damage pos is larger than damage count") }
+                
+                calcHP(damage: damages[damagePos], receive: damage)
+                
+                Debug.excute(level: .debug) {
+                    
+                    let shipOffset = (battleFleet == .second) ? 6 : 0
+                    print("Hougeki \(targetPos + shipOffset) -> \(damage)")
+                }
+            }
+        }
+    }
+    
+    fileprivate func calculateFDam(baseKeyPath: String, _ bf: () -> BattleFleet) {
+        
+        calculateFDam(baseKeyPath: baseKeyPath, battleFleet: bf())
+    }
+    
+    fileprivate func calculateFDam(baseKeyPath: String, battleFleet: BattleFleet = .first) {
+        
+        let baseValue = json[baseKeyPath.components(separatedBy: ".")]
+        
+        guard let koukuDamages = baseValue["api_fdam"].arrayObject as? [Int]
+            else { return }
+        
+        Debug.print("Start FDam \(baseKeyPath)", level: .debug)
+        
+        koukuDamages.enumerated().forEach { (idx, damage) in
+            
+            if idx == 0 { return }
+            
+            guard let damagePos = position(idx, in: battleFleet)
+                else { return }
+            
+            calcHP(damage: damages[damagePos], receive: damage)
+            
+            Debug.excute(level: .debug) {
+                
+                let shipOffset = (battleFleet == .second) ? 6 : 0
+                print("FDam \(idx + shipOffset) -> \(damage)")
+            }
+        }
     }
 }
+
+
 // MARK: - Damage control
-extension CalculateDamageCommand {
+extension DamageCalculator {
+    
     fileprivate func damageControlIfPossible(nowhp: Int, ship: Ship) -> Int {
+        
         var nowHp = nowhp
         if nowHp < 0 { nowHp = 0 }
         let maxhp = ship.maxhp
         let store = ServerDataStore.default
         var useDamageControl = false
+        
         ship.equippedItem.forEach {
+            
             if useDamageControl { return }
-            guard let master = $0 as? SlotItem else { return }
+            
+            guard let master = $0 as? SlotItem
+                else { return }
+            
             let masterSlotItemId = store.masterSlotItemID(by: master.id)
+            
             guard let type = DamageControlID(rawValue: masterSlotItemId)
                 else { return }
+            
             switch type {
             case .damageControl:
                 nowHp = Int(Double(maxhp) * 0.2)
                 useDamageControl = true
+                
             case .goddes:
                 nowHp = maxhp
                 useDamageControl = true
             }
         }
+        
         if useDamageControl { return nowHp }
+        
         // check extra slot
         let exItemId = store.masterSlotItemID(by: ship.slot_ex)
+        
         guard let exType = DamageControlID(rawValue: exItemId)
             else { return nowHp }
+        
         switch exType {
         case .damageControl:
             nowHp = Int(Double(maxhp) * 0.2)
+            
         case .goddes:
             nowHp = maxhp
         }
+        
         return nowHp
     }
-    func removeFirstDamageControl(of ship: Ship) {
-        let equiped = ship.equippedItem
-        let newEquiped = equiped.array
-        let store = ServerDataStore.default
-        var useDamageControl = false
-        equiped.forEach {
-            if useDamageControl { return }
-            guard let master = $0 as? SlotItem else { return }
-            let masterSlotItemId = store.masterSlotItemID(by: master.id)
-            guard let type = DamageControlID(rawValue: masterSlotItemId)
-                else { return }
-            switch type {
-            case .goddes:
-                ship.fuel = ship.maxFuel
-                ship.bull = ship.maxBull
-                fallthrough
-            case .damageControl:
-                if var equiped = newEquiped as? [SlotItem],
-                    let index = equiped.index(of: master) {
-                    equiped[index...index] = []
-                    ship.equippedItem = NSOrderedSet(array: equiped)
-                    useDamageControl = true
-                }
-            }
-        }
-        if useDamageControl { return }
-        // check extra slot
-        let exItemId = store.masterSlotItemID(by: ship.slot_ex)
-        guard let exType = DamageControlID(rawValue: exItemId)
-            else { return }
-        switch exType {
-        case .goddes:
-            ship.fuel = ship.maxFuel
-            ship.bull = ship.maxBull
-            fallthrough
-        case .damageControl:
-            ship.slot_ex = -1
-        }
-    }
 }