5 // Created by Hori,Masaki on 2017/01/29.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
11 // swiftlint:disable variable_name
12 final class Ship: KCManagedObject {
14 @NSManaged dynamic var bull: Int
15 @NSManaged dynamic var cond: Int
16 @NSManaged dynamic var exp: Int
17 @NSManaged dynamic var fleet: NSNumber?
18 @NSManaged dynamic var fuel: Int
19 @NSManaged dynamic var id: Int
20 @NSManaged dynamic var kaihi_0: Int
21 @NSManaged dynamic var kaihi_1: NSNumber?
22 @NSManaged dynamic var karyoku_0: Int
23 @NSManaged dynamic var karyoku_1: Int
24 @NSManaged dynamic var kyouka_0: Int
25 @NSManaged dynamic var kyouka_1: Int
26 @NSManaged dynamic var kyouka_2: Int
27 @NSManaged dynamic var kyouka_3: Int
28 @NSManaged dynamic var kyouka_4: Int
29 @NSManaged dynamic var locked: Int
30 @NSManaged dynamic var locked_equip: NSNumber?
31 @NSManaged dynamic var lucky_0: Int
32 @NSManaged dynamic var lucky_1: Int
33 @NSManaged dynamic var lv: Int
34 @NSManaged dynamic var maxhp: Int
35 @NSManaged dynamic var ndock_time: NSNumber?
36 @NSManaged dynamic var nowhp: Int
37 @NSManaged dynamic var onslot_0: Int
38 @NSManaged dynamic var onslot_1: Int
39 @NSManaged dynamic var onslot_2: Int
40 @NSManaged dynamic var onslot_3: Int
41 @NSManaged dynamic var onslot_4: Int
42 @NSManaged dynamic var raisou_0: Int
43 @NSManaged dynamic var raisou_1: Int
44 @NSManaged dynamic var sakuteki_0: Int
45 @NSManaged dynamic var sakuteki_1: NSNumber?
46 @NSManaged dynamic var sally_area: NSNumber?
47 @NSManaged dynamic var ship_id: Int
48 @NSManaged dynamic var slot_0: Int
49 @NSManaged dynamic var slot_1: Int
50 @NSManaged dynamic var slot_2: Int
51 @NSManaged dynamic var slot_3: Int
52 @NSManaged dynamic var slot_4: Int
53 @NSManaged dynamic var slot_ex: Int
54 @NSManaged dynamic var sortno: NSNumber?
55 @NSManaged dynamic var soukou_0: Int
56 @NSManaged dynamic var soukou_1: Int
57 @NSManaged dynamic var srate: NSNumber?
58 @NSManaged dynamic var taiku_0: Int
59 @NSManaged dynamic var taiku_1: Int
60 @NSManaged dynamic var taisen_0: Int
61 @NSManaged dynamic var taisen_1: NSNumber?
62 @NSManaged dynamic var equippedItem: NSOrderedSet
63 @NSManaged dynamic var master_ship: MasterShip
64 @NSManaged dynamic var extraItem: SlotItem?
66 // swiftlint:eable variable_name
68 private let shortSTypeNames: [String] = {
70 guard let url = Bundle.main.url(forResource: "STypeShortName", withExtension: "plist"),
71 let array = NSArray(contentsOf: url) as? [String] else {
73 return Logger.shared.log("Can not load STypeShortName.plist.", value: [])
79 private let levelUpExps: [Int] = {
81 guard let url = Bundle.main.url(forResource: "LevelUpExp", withExtension: "plist"),
82 let array = NSArray(contentsOf: url) as? [Int] else {
84 return Logger.shared.log("Can not load LevelUpExp.plist.", value: [])
92 @objc override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
96 case #keyPath(name): return [#keyPath(ship_id)]
98 case #keyPath(shortTypeName): return [#keyPath(ship_id)]
100 case #keyPath(next): return [#keyPath(exp)]
102 case #keyPath(status): return [#keyPath(nowhp), #keyPath(maxhp)]
104 case #keyPath(planColor): return [#keyPath(sally_area)]
106 case #keyPath(isMaxKaryoku): return [#keyPath(karyoku_1), #keyPath(kyouka_0)]
108 case #keyPath(isMaxRaisou): return [#keyPath(raisou_1), #keyPath(kyouka_1)]
110 case #keyPath(isMaxTaiku): return [#keyPath(taiku_1), #keyPath(kyouka_2)]
112 case #keyPath(isMaxSoukou): return [#keyPath(soukou_1), #keyPath(kyouka_3)]
114 case #keyPath(isMaxLucky): return [#keyPath(lucky_1), #keyPath(kyouka_4)]
116 case #keyPath(upgradeLevel): return [#keyPath(ship_id)]
118 case #keyPath(upgradeExp): return [#keyPath(exp)]
120 case #keyPath(steelRequiredInRepair): return [#keyPath(nowhp)]
122 case #keyPath(fuelRequiredInRepair): return [#keyPath(nowhp)]
124 case #keyPath(seiku): return [#keyPath(slot_0), #keyPath(slot_1), #keyPath(slot_2), #keyPath(slot_3), #keyPath(slot_4),
125 #keyPath(onslot_0), #keyPath(onslot_1), #keyPath(onslot_2), #keyPath(onslot_3), #keyPath(onslot_4)]
132 @objc dynamic var name: String { return master_ship.name }
134 @objc dynamic var shortTypeName: String? {
136 let index = master_ship.stype.id - 1
138 guard case 0..<shortSTypeNames.count = index else { return nil }
140 return shortSTypeNames[index]
143 @objc dynamic var next: NSNumber? {
145 guard case 0..<levelUpExps.count = lv else { return nil }
147 if lv == 99 { return nil }
149 let nextExp = levelUpExps[lv]
151 if lv < 99 { return (nextExp - exp) as NSNumber }
153 return (1_000_000 + nextExp - exp) as NSNumber
156 @objc dynamic var status: Int {
158 let stat = Double(nowhp) / Double(maxhp)
160 if stat <= 0.25 { return 3 }
161 if stat <= 0.5 { return 2 }
162 if stat <= 0.75 { return 1 }
167 @objc dynamic var planColor: NSColor {
169 if !UserDefaults.standard[.showsPlanColor] { return .controlTextColor }
171 guard let sally = sally_area else { return .controlTextColor }
174 case 1: return UserDefaults.standard[.plan01Color]
175 case 2: return UserDefaults.standard[.plan02Color]
176 case 3: return UserDefaults.standard[.plan03Color]
177 case 4: return UserDefaults.standard[.plan04Color]
178 case 5: return UserDefaults.standard[.plan05Color]
179 case 6: return UserDefaults.standard[.plan06Color]
180 default: return .controlTextColor
188 @objc dynamic var maxBull: Int { return master_ship.bull_max }
189 @objc dynamic var maxFuel: Int { return master_ship.fuel_max }
191 @objc dynamic var isMaxKaryoku: Bool {
193 let initial = master_ship.houg_0
195 let growth = kyouka_0
197 return initial + growth >= max
200 @objc dynamic var isMaxRaisou: Bool {
202 let initial = master_ship.raig_0
204 let growth = kyouka_1
206 return initial + growth >= max
209 @objc dynamic var isMaxTaiku: Bool {
211 let initial = master_ship.tyku_0
213 let growth = kyouka_2
215 return initial + growth >= max
218 @objc dynamic var isMaxSoukou: Bool {
220 let initial = master_ship.souk_0
222 let growth = kyouka_3
224 return initial + growth >= max
227 @objc dynamic var isMaxLucky: Bool {
229 let initial = master_ship.luck_0
231 let growth = kyouka_4
233 return initial + growth >= max
236 @objc dynamic var upgradeLevel: Int { return master_ship.afterlv }
238 @objc dynamic var upgradeExp: NSNumber? {
240 let upgradeLv = upgradeLevel
242 if upgradeLv <= 0 { return nil }
243 if levelUpExps.count < upgradeLv { return nil }
245 let upExp = levelUpExps[upgradeLv - 1] - exp
247 return upExp < 0 ? 0 : upExp as NSNumber
250 @objc dynamic var guardEscaped: Bool {
252 let store = TemporaryDataStore.default
254 guard let _ = store.ensuredGuardEscaped(byShipId: id) else { return false }
259 @objc dynamic var steelRequiredInRepair: Int {
261 return Int(Double(maxFuel) * 0.06 * Double(maxhp - nowhp))
264 @objc dynamic var fuelRequiredInRepair: Int {
266 return Int(Double(maxFuel) * 0.032 * Double(maxhp - nowhp))
272 func setItem(_ id: Int, to slot: Int) {
280 default: fatalError("Ship: setItem out of bounds.")
284 func slotItemId(_ index: Int) -> Int {
287 case 0: return slot_0
288 case 1: return slot_1
289 case 2: return slot_2
290 case 3: return slot_3
291 case 4: return slot_4
296 func slotItemCount(_ index: Int) -> Int {
299 case 0: return onslot_0
300 case 1: return onslot_1
301 case 2: return onslot_2
302 case 3: return onslot_3
303 case 4: return onslot_4
308 func slotItemMax(_ index: Int) -> Int {
311 case 0: return master_ship.maxeq_0
312 case 1: return master_ship.maxeq_1
313 case 2: return master_ship.maxeq_2
314 case 3: return master_ship.maxeq_3
315 case 4: return master_ship.maxeq_4
320 func slotItem(_ index: Int) -> SlotItem? {
322 return ServerDataStore.default.slotItem(by: slotItemId(index))
325 @objc dynamic var totalEquipment: Int {
327 return (0...4).map(slotItemMax).reduce(0, +)
330 @objc dynamic var seiku: Int {
332 return SeikuCalclator(ship: self).seiku