From 3955a3fcc4c1d5e96f4b1f07d9f9699c62e481b4 Mon Sep 17 00:00:00 2001 From: masakih Date: Sun, 23 Jul 2017 19:47:21 +0900 Subject: [PATCH] =?utf8?q?=E3=83=80=E3=83=A1=E3=83=BC=E3=82=B8=E8=A8=88?= =?utf8?q?=E7=AE=97=E9=83=A8=E5=88=86=E3=82=92=E5=88=A5=E3=82=AF=E3=83=A9?= =?utf8?q?=E3=82=B9=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- KCD/CalculateDamageCommand.swift | 213 ++++++++++------- KCD/DamageCalculator.swift | 505 +++++++++++++++++++++++++-------------- 2 files changed, 462 insertions(+), 256 deletions(-) diff --git a/KCD/CalculateDamageCommand.swift b/KCD/CalculateDamageCommand.swift index 3c218266..673dd3f0 100644 --- a/KCD/CalculateDamageCommand.swift +++ b/KCD/CalculateDamageCommand.swift @@ -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 + } + } } diff --git a/KCD/DamageCalculator.swift b/KCD/DamageCalculator.swift index f18a614d..0d560d8c 100644 --- a/KCD/DamageCalculator.swift +++ b/KCD/DamageCalculator.swift @@ -9,116 +9,80 @@ 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.. 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.. 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.. 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.. 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 - } - } } -- 2.11.0