@@ -193,20 +193,22 @@ def __eq__(self, other):
193193 def __hash__ (self ):
194194 return hash ((self .__name , self .__level , self .__village , self .__is_active ))
195195
196+
196197 @classmethod
197- def _load_json_meta (cls , json_meta , id , name , lab_to_townhall ):
198+ def _load_json_meta (cls , json_meta : dict , id , name : str , lab_to_townhall ):
198199 cls .id = int (id )
199200 cls .name = name
200201 cls .lab_to_townhall = lab_to_townhall
201202
202- cls .range = try_enum (UnitStat , json_meta .get ("AttackRange" ))
203- cls .dps = try_enum (UnitStat , json_meta .get ("DPS" ))
204- cls .ground_target = _get_maybe_first (json_meta , "GroundTargets" ,
205- default = True )
206- cls .hitpoints = try_enum (UnitStat , json_meta .get ("Hitpoints" ))
203+ levels_available = [key for key in json_meta .keys () if key .isnumeric ()]
204+
205+ cls .ground_target = json_meta .get ("GroundTargets" , True )
206+ cls .range = try_enum (UnitStat , [json_meta .get (level ).get ("AttackRange" ) for level in levels_available ])
207+ cls .dps = try_enum (UnitStat , [json_meta .get (level ).get ("DPS" ) for level in levels_available ])
208+ cls .hitpoints = try_enum (UnitStat , [json_meta .get (level ).get ("Hitpoints" ) for level in levels_available ])
207209
208210 # get production building
209- production_building = json_meta .get ("ProductionBuilding" , [ None ])[ 0 ] if json_meta . get ( "ProductionBuilding" ) else None
211+ production_building = json_meta .get ("ProductionBuilding" )
210212 if production_building == "Barrack" :
211213 cls .is_elixir_troop = True
212214 elif production_building == "Dark Elixir Barrack" :
@@ -226,75 +228,79 @@ def _load_json_meta(cls, json_meta, id, name, lab_to_townhall):
226228
227229 # without production_building, it is a hero
228230 if not production_building :
229- laboratory_levels = json_meta .get ("LaboratoryLevel" )
231+ laboratory_levels = [ json_meta .get (level ). get ( "LaboratoryLevel" ) for level in levels_available ]
230232 else :
231- # it is a troop or spell or siege
232233 prod_unit = buildings .get (production_building )
233234 if production_building in ("SiegeWorkshop" , "Spell Forge" , "Mini Spell Factory" ,
234235 "Dark Elixir Barrack" , "Barrack" , "Barrack2" ):
235- min_prod_unit_level = json_meta .get ("BarrackLevel" , [ None , ])[ 0 ]
236+ min_prod_unit_level = json_meta .get ("BarrackLevel" , None )
236237 # there are some special troops, which have no BarrackLevel attribute
237238 if not min_prod_unit_level :
238- laboratory_levels = json_meta .get ("LaboratoryLevel" )
239+ laboratory_levels = [ json_meta .get (level ). get ( "LaboratoryLevel" ) for level in levels_available ]
239240 else :
240- # get the min th level were we can unlock by the required level of the production building
241- min_th_level = [th for i , th in
242- enumerate (prod_unit ["TownHallLevel" ], start = 1 )
243- if i == min_prod_unit_level ]
241+ #get the townhall level of the spot where prod building level is equal to the one of the unit
242+ min_th_level = prod_unit .get (str (min_prod_unit_level )).get ("TownHallLevel" , 0 )
244243 # map the min th level to a lab level
245- [first_lab_level ] = [lab_level for lab_level , th_level in
246- lab_to_townhall .items ()
247- if th_level in min_th_level ]
244+ [first_lab_level ] = [lab_level for lab_level , th_level in lab_to_townhall .items () if th_level == min_th_level ]
248245 # the first_lab_level is the lowest possible (there are some inconsistencies with siege machines)
249246 # To handle them properly, replacing all lab_level lower than first_lab_level with first_lab_level
250247 laboratory_levels = []
251- for lab_level in json_meta .get ("LaboratoryLevel" ) :
248+ for lab_level in [ json_meta .get (level ). get ( "LaboratoryLevel" , 1 ) for level in levels_available ] :
252249 laboratory_levels .append (max (lab_level , first_lab_level ))
250+
251+
252+
253+
253254 elif production_building == "Pet Shop" :
254- min_prod_unit_level = json_meta .get ("LaboratoryLevel" , [None , ])[0 ]
255- # there are some special troops, which have no BarrackLevel attribute
255+ min_prod_unit_level = json_meta .get ("1" ).get ("LaboratoryLevel" )
256256
257257 # get the min th level were we can unlock by the required level of the production building
258- min_th_level = [th for i , th in
259- enumerate (prod_unit ["TownHallLevel" ], start = 1 )
260- if i == min_prod_unit_level ]
258+ min_th_level = prod_unit .get (str (min_prod_unit_level )).get ("TownHallLevel" , 0 )
259+
261260 # map the min th level to a lab level
262- [first_lab_level ] = [lab_level for lab_level , th_level in
263- lab_to_townhall .items ()
264- if th_level in min_th_level ]
261+ [first_lab_level ] = [lab_level for lab_level , th_level in lab_to_townhall .items () if th_level == min_th_level ]
265262 # the first_lab_level is the lowest possible (there are some inconsistencies with siege machines)
266263 # To handle them properly, replacing all lab_level lower than first_lab_level with first_lab_level
267264 laboratory_levels = []
268- for lab_level in json_meta .get ("LaboratoryLevel" ):
265+ for lab_level in [ json_meta .get (level ). get ( "LaboratoryLevel" ) for level in levels_available ] :
269266 laboratory_levels .append (max (lab_level , first_lab_level ))
267+
270268 else :
271269 return
272270
273271 cls .lab_level = try_enum (UnitStat , laboratory_levels )
274- cls .housing_space = _get_maybe_first (json_meta , "HousingSpace" , default = 0 )
275- cls .speed = try_enum (UnitStat , json_meta .get ("Speed" ))
272+ cls .housing_space = json_meta .get ("HousingSpace" , 0 )
273+
274+ cls .speed = try_enum (UnitStat , [json_meta .get (level ).get ("Speed" ) for level in levels_available ])
276275 cls .level = cls .dps and UnitStat (range (1 , len (cls .dps ) + 1 ))
277276
278- # all 3
279- cls .upgrade_cost = try_enum (UnitStat , json_meta .get ("UpgradeCost" ))
280- cls .upgrade_resource = Resource (value = json_meta ["UpgradeResource" ][0 ])
281- cls .upgrade_time = try_enum (UnitStat ,
282- [TimeDelta (hours = hours ) for hours in
283- json_meta .get ("UpgradeTimeH" , [])])
277+ cls .upgrade_cost = try_enum (UnitStat , [json_meta .get (level ).get ("UpgradeCost" ) for level in levels_available ])
278+ cls .upgrade_resource = Resource (value = json_meta .get ("UpgradeResource" ))
279+ upgrade_times = [
280+ TimeDelta (hours = json_meta .get (level , {}).get ("UpgradeTimeH" ))
281+ for level in levels_available
282+ if json_meta .get (level , {}).get ("UpgradeTimeH" ) is not None
283+ ]
284+ cls .upgrade_time = try_enum (UnitStat , upgrade_times )
285+
284286 cls ._is_home_village = False if json_meta .get ("VillageType" ) else True
285287 cls .village = "home" if cls ._is_home_village else "builderBase"
286288
287- # spells and troops
288- cls .training_cost = try_enum (UnitStat , json_meta .get ("TrainingCost" ))
289- cls .training_time = try_enum (UnitStat , json_meta .get ("TrainingTime" ))
289+ cls .training_time = TimeDelta (seconds = json_meta .get ("TrainingTime" ))
290290
291291 # only heroes
292- cls .ability_time = try_enum (UnitStat , json_meta .get ("AbilityTime" ))
293- cls .ability_troop_count = try_enum (UnitStat , json_meta .get ("AbilitySummonTroopCount" ))
294- cls .required_th_level = try_enum (UnitStat , json_meta .get ("RequiredTownHallLevel" ) or laboratory_levels )
295- cls .regeneration_time = try_enum (
296- UnitStat , [TimeDelta (minutes = value ) for value in json_meta .get ("RegenerationTimeMinutes" , [])]
297- )
292+ cls .ability_time = try_enum (UnitStat , [json_meta .get (level ).get ("AbilityTime" ) for level in levels_available ])
293+ cls .ability_troop_count = try_enum (UnitStat , [json_meta .get (level ).get ("AbilitySummonTroopCount" ) for level in levels_available ])
294+
295+ required_townhall_levels = [json_meta .get (level ).get ("RequiredTownHallLevel" ) for level in levels_available ]
296+ cls .required_th_level = try_enum (UnitStat , required_townhall_levels if any (required_townhall_levels ) else laboratory_levels )
297+
298+ regeneration_times = [
299+ TimeDelta (minutes = json_meta .get (level , {}).get ("RegenerationTimeMinutes" ))
300+ for level in levels_available
301+ if json_meta .get (level , {}).get ("RegenerationTimeMinutes" ) is not None
302+ ]
303+ cls .regeneration_time = try_enum (UnitStat , regeneration_times )
298304
299305 cls .is_loaded = True
300306 return cls
@@ -355,11 +361,11 @@ def _load_json(self, english_aliases, lab_to_townhall):
355361 continue
356362
357363 # SC game files have "DisableProduction" true for all pet objects, which we want
358- if True in meta .get ("DisableProduction" , [ False ] ) and "pets" not in str (self .FILE_PATH ):
364+ if meta .get ("DisableProduction" ) and "pets" not in str (self .FILE_PATH ):
359365 continue
360366
361367 # ignore deprecated content
362- if True in meta .get ("Deprecated" , [ False ] ):
368+ if meta .get ("Deprecated" ):
363369 continue
364370
365371 #hacky but the aliases convert so that isnt great
@@ -374,7 +380,7 @@ def _load_json(self, english_aliases, lab_to_townhall):
374380 new_item ._load_json_meta (
375381 meta ,
376382 id = id ,
377- name = english_aliases [meta [ "TID" ][ 0 ]][ "EN" ][ 0 ],
383+ name = english_aliases [meta . get ( "TID" ) ],
378384 lab_to_townhall = lab_to_townhall ,
379385 )
380386 id += 1
0 commit comments