2222SOFTWARE.
2323"""
2424import ujson
25-
25+ from pathlib import Path
2626from typing import AsyncIterator , Any , Dict , Type , Optional , TYPE_CHECKING
2727
2828from .enums import Resource
3333if TYPE_CHECKING :
3434 from .players import Player
3535
36+ BUILDING_FILE_PATH = Path (__file__ ).parent .joinpath (Path ("static/buildings.json" ))
37+
3638
3739class BaseClan :
3840 """An ABC that implements some common operations on clans, regardless of type.
@@ -187,8 +189,47 @@ def _load_json_meta(cls, troop_meta, id, name, lab_to_townhall):
187189 cls .ground_target = _get_maybe_first (troop_meta , "GroundTargets" , default = True )
188190 cls .hitpoints = try_enum (UnitStat , troop_meta .get ("Hitpoints" ))
189191
192+ # get production building
193+ production_building = troop_meta .get ("ProductionBuilding" , [None ])[0 ]
194+ if production_building == "Barrack" :
195+ cls .is_elixir_troop = True
196+ elif production_building == "Dark Elixir Barrack" :
197+ cls .is_dark_troop = True
198+ elif production_building == "SiegeWorkshop" :
199+ cls .is_siege_machine = True
200+ elif production_building == "Spell Forge" :
201+ cls .is_elixir_spell = True
202+ elif production_building == "Mini Spell Factory" :
203+ cls .is_dark_spell = True
204+
205+ # load buildings
206+ with open (BUILDING_FILE_PATH ) as fp :
207+ buildings = ujson .load (fp )
208+
209+ # without production_building, it is a hero or pet
210+ if not production_building :
211+ laboratory_levels = troop_meta .get ("LaboratoryLevel" )
212+ else :
213+ # it is a troop or spell
214+ prod_unit = buildings .get (production_building )
215+ min_prod_unit_level = troop_meta .get ("BarrackLevel" , [None , ])[0 ]
216+ # there are some special troops, which have no BarrackLevel attribute
217+ if not min_prod_unit_level :
218+ laboratory_levels = troop_meta .get ("LaboratoryLevel" )
219+ else :
220+ # get the min th level were we can unlock by the required level of the production building
221+ min_th_level = [th for i , th in enumerate (prod_unit ["TownHallLevel" ], start = 1 )
222+ if i == min_prod_unit_level ]
223+ # map the min th level to a lab level
224+ [first_lab_level ] = [lab_level for lab_level , th_level in lab_to_townhall .items ()
225+ if th_level in min_th_level ]
226+ # the first_lab_level is the lowest possible (there are some inconsistencies with siege machines)
227+ # To handle them properly, replacing all lab_level lower than first_lab_level with first_lab_level
228+ laboratory_levels = [x if x > first_lab_level else first_lab_level
229+ for x in troop_meta .get ("LaboratoryLevel" )]
230+
231+ cls .lab_level = try_enum (UnitStat , laboratory_levels )
190232 cls .housing_space = _get_maybe_first (troop_meta , "HousingSpace" , default = 0 )
191- cls .lab_level = try_enum (UnitStat , troop_meta .get ("LaboratoryLevel" ))
192233 cls .speed = try_enum (UnitStat , troop_meta .get ("Speed" ))
193234 cls .level = cls .dps and UnitStat (range (1 , len (cls .dps ) + 1 ))
194235
@@ -197,6 +238,7 @@ def _load_json_meta(cls, troop_meta, id, name, lab_to_townhall):
197238 cls .upgrade_resource = Resource (value = troop_meta ["UpgradeResource" ][0 ])
198239 cls .upgrade_time = try_enum (UnitStat , [TimeDelta (hours = hours ) for hours in troop_meta .get ("UpgradeTimeH" , [])])
199240 cls ._is_home_village = False if troop_meta .get ("VillageType" ) else True
241+ cls .village = "home" if cls ._is_home_village else "builderBase"
200242
201243 # spells and troops
202244 cls .training_cost = try_enum (UnitStat , troop_meta .get ("TrainingCost" ))
@@ -208,18 +250,6 @@ def _load_json_meta(cls, troop_meta, id, name, lab_to_townhall):
208250 cls .required_th_level = try_enum (UnitStat , troop_meta .get ("RequiredTownHallLevel" ))
209251 cls .regeneration_time = try_enum (UnitStat , [TimeDelta (minutes = value ) for value in troop_meta .get ("RegenerationTimeMinutes" , [])])
210252
211- production_building = troop_meta .get ("ProductionBuilding" , [None ])[0 ]
212- if production_building == "Barrack" :
213- cls .is_elixir_troop = True
214- elif production_building == "Dark Elixir Barrack" :
215- cls .is_dark_troop = True
216- elif production_building == "SiegeWorkshop" :
217- cls .is_siege_machine = True
218- elif production_building == "Spell Forge" :
219- cls .is_elixir_spell = True
220- elif production_building == "Mini Spell Factory" :
221- cls .is_dark_spell = True
222-
223253 cls .is_loaded = True
224254 return cls
225255
0 commit comments