def __init__(self, xmldoc): Unit.__init__(self) # This is a mech self.type = "BM" # Set some data to zero that sometimes will not get set otherwise self.multi = Multi() # Get top-level structure data for mmech in xmldoc.getElementsByTagName('mech'): self.model = mmech.attributes["model"].value self.name = mmech.attributes["name"].value self.omni = mmech.attributes["omnimech"].value self.weight = int(mmech.attributes["tons"].value) # Get BV. Should give prime variant BV for Omni-mechs # get first instance only to avoid problems with Omni-mechs self.batt_val = int(get_child_data(mmech, 'battle_value')) # Get Cost. cost = float(get_child_data(mmech, 'cost')) # Get production era self.prod_era = int(get_child_data(mmech, 'productionera')) # Get mech type (battle, industrial) self.mechtype = get_child_data(mmech, 'mech_type') # Only support battlemechs if (self.mechtype != "BattleMech" and self.mechtype != "PrimitiveBattleMech"): print self.name, self.model print "Industrial Mechs not supported!" sys.exit(1) # Get techbase (IS, Clan) # get first instance only to avoid problems with Omni-mechs self.techbase = get_child_data(mmech, 'techbase') # Get year self.year = int(get_child_data(mmech, 'year')) # Sanity check for year year_era_test(self.year, self.prod_era, self.name + " " + self.model) if (self.year < 2439): print self.name, self.model print "Battlemech older than Mackie!" sys.exit(1) if (self.year < 2470 and self.mechtype == "BattleMech"): print self.name, self.model print "Non-primitive BattleMechs not available before 2470!" sys.exit(1) if (self.year < 2854 and self.omni == "TRUE"): print self.name, self.model print "OmniMechs not available before 2854!" sys.exit(1) # Get motive type (biped, quad) self.motive = get_child_data(mmech, 'motive_type') ### Components starts here ### # Get internal structure type self.structure = MechStructure(get_child(mmech, 'structure'), self.weight, self.motive) # Get engine data self.engine = Engine(get_child(mmech, 'engine'), self) # Get gyro self.gyro = Gyro(get_child(mmech, 'gyro'), self.engine.etype, self.engine.erating) # Get cockpit self.cockpit = Cockpit(get_child(mmech, 'cockpit'), self) # Get enhancement, needs for loop self.enhancement = Enhancement(None, self.weight, self.engine.erating) for enh in mmech.getElementsByTagName('enhancement'): self.enhancement = Enhancement(enh, self.weight, self.engine.erating) # Get armor. self.armor = MechArmor(get_child(mmech, 'armor'), self.weight, self.motive) ### Loadout stuff starts here ### # Get baseloadout blo = mmech.getElementsByTagName('baseloadout')[0] # Get multi-slot stuff for mlts in blo.getElementsByTagName('multislot'): slot = mlts.attributes["name"].value self.multi.add(slot) # Construct current loadout, empty name for base loadout self.load = Baseloadout(blo, self, self.batt_val, self.prod_era, cost) # HACK -- Apply modular armor if self.load.gear.has_mod_armor: self.armor.apply_modular(self.load.gear.mod_armor) # Get omni loadouts self.loads = [] for load in mmech.getElementsByTagName('loadout'): # Construct current loadout current = Loadout(load, self.load, self) self.loads.append(current)
class Mech(Unit): """ A master class holding info about a mech. """ def __init__(self, xmldoc): Unit.__init__(self) # This is a mech self.type = "BM" # Set some data to zero that sometimes will not get set otherwise self.multi = Multi() # Get top-level structure data for mmech in xmldoc.getElementsByTagName('mech'): self.model = mmech.attributes["model"].value self.name = mmech.attributes["name"].value self.omni = mmech.attributes["omnimech"].value self.weight = int(mmech.attributes["tons"].value) # Get BV. Should give prime variant BV for Omni-mechs # get first instance only to avoid problems with Omni-mechs self.batt_val = int(get_child_data(mmech, 'battle_value')) # Get Cost. cost = float(get_child_data(mmech, 'cost')) # Get production era self.prod_era = int(get_child_data(mmech, 'productionera')) # Get mech type (battle, industrial) self.mechtype = get_child_data(mmech, 'mech_type') # Only support battlemechs if (self.mechtype != "BattleMech" and self.mechtype != "PrimitiveBattleMech"): print self.name, self.model print "Industrial Mechs not supported!" sys.exit(1) # Get techbase (IS, Clan) # get first instance only to avoid problems with Omni-mechs self.techbase = get_child_data(mmech, 'techbase') # Get year self.year = int(get_child_data(mmech, 'year')) # Sanity check for year year_era_test(self.year, self.prod_era, self.name + " " + self.model) if (self.year < 2439): print self.name, self.model print "Battlemech older than Mackie!" sys.exit(1) if (self.year < 2470 and self.mechtype == "BattleMech"): print self.name, self.model print "Non-primitive BattleMechs not available before 2470!" sys.exit(1) if (self.year < 2854 and self.omni == "TRUE"): print self.name, self.model print "OmniMechs not available before 2854!" sys.exit(1) # Get motive type (biped, quad) self.motive = get_child_data(mmech, 'motive_type') ### Components starts here ### # Get internal structure type self.structure = MechStructure(get_child(mmech, 'structure'), self.weight, self.motive) # Get engine data self.engine = Engine(get_child(mmech, 'engine'), self) # Get gyro self.gyro = Gyro(get_child(mmech, 'gyro'), self.engine.etype, self.engine.erating) # Get cockpit self.cockpit = Cockpit(get_child(mmech, 'cockpit'), self) # Get enhancement, needs for loop self.enhancement = Enhancement(None, self.weight, self.engine.erating) for enh in mmech.getElementsByTagName('enhancement'): self.enhancement = Enhancement(enh, self.weight, self.engine.erating) # Get armor. self.armor = MechArmor(get_child(mmech, 'armor'), self.weight, self.motive) ### Loadout stuff starts here ### # Get baseloadout blo = mmech.getElementsByTagName('baseloadout')[0] # Get multi-slot stuff for mlts in blo.getElementsByTagName('multislot'): slot = mlts.attributes["name"].value self.multi.add(slot) # Construct current loadout, empty name for base loadout self.load = Baseloadout(blo, self, self.batt_val, self.prod_era, cost) # HACK -- Apply modular armor if self.load.gear.has_mod_armor: self.armor.apply_modular(self.load.gear.mod_armor) # Get omni loadouts self.loads = [] for load in mmech.getElementsByTagName('loadout'): # Construct current loadout current = Loadout(load, self.load, self) self.loads.append(current) def get_walk(self): """ Get walk speed """ return self.engine.speed + self.load.gear.get_speed_adj() def get_run(self): """ Get standard running speed, with no modifiers """ spd = self.engine.speed + self.load.gear.get_speed_adj() factor = 1.5 rspeed = int(ceil(spd * factor)) # Hardened Armor if self.armor.atype == "Hardened Armor": rspeed -= 1 return rspeed def get_max_run(self, load): """ Get maximum running speed """ spd = self.engine.speed + self.load.gear.get_speed_adj() factor = 1.5 if self.enhancement.is_tsm(): spd += 1 elif self.enhancement.is_masc(): factor += 0.5 if (self.load.gear.supercharger.has_sc() or load.gear.supercharger.has_sc()): factor += 0.5 rspeed = int(ceil(spd * factor)) # Hardened Armor if self.armor.atype == "Hardened Armor": rspeed -= 1 return rspeed def get_move_target_modifier(self, load): """ Get target modifier from movement, see Total Warfare for details """ run_speed = self.get_max_run(load) jump_speed = load.get_jump() r_mod = get_move_target_modifier(run_speed) j_mod = get_move_target_modifier(jump_speed) # Do not give jump mods if no jumpjets if (jump_speed > 0): j_mod += 1 return max(j_mod, r_mod) def get_stealth(self): """ Returns true if the mech mounts a stealth system """ stlth = False if self.multi.get_stealth(): stlth = True if self.armor.atype == "Stealth Armor": stlth = True return stlth def def_bv(self, load, printq): """ Get defensive BV """ dbv = 0.0 # Armor torso_cockpit = False if self.cockpit.type == "Torso-Mounted Cockpit": torso_cockpit = True # HACK -- Apply modular armor if load.gear.has_mod_armor: self.armor.apply_modular(load.gear.mod_armor) cur = self.armor.get_armor_bv(torso_cockpit) dbv += cur if (printq): print "Armor Def BV: ", cur # HACK -- Remove modular armor if load.gear.has_mod_armor: self.armor.remove_modular(load.gear.mod_armor) # Internal cur = self.structure.get_bv_factor() * self.engine.get_bv_mod() dbv += cur if (printq): print "Internal Def BV: ", cur # Gyro cur = self.weight * self.gyro.get_bv_mod() if (load.arm_gyro and (self.gyro.gtype == "Standard Gyro" or self.gyro.gtype == "Heavy-Duty Gyro")): cur *= 1.20 elif (load.arm_gyro and self.gyro.gtype == "Compact Gyro"): cur *= 1.10 elif (load.arm_gyro and self.gyro.gtype == "Extra-Light Gyro"): cur *= 1.30 dbv += cur if (printq): print "Gyro Def BV: ", cur # Defensive equipment cur = load.get_def_bv(self) dbv += cur if (printq): print "Equipment Def BV: ", cur # Explosive cur = load.gear.get_ammo_exp_bv(self.engine) dbv += cur if (printq): print "Explosive Ammo BV: ", cur cur = load.gear.get_weapon_exp_bv(self.engine) dbv += cur if (printq): print "Explosive Weapon BV: ", cur # Defensive factor mtm = self.get_move_target_modifier(load) # Stealth armor adds to to-hit if self.armor.atype == "Stealth Armor": mtm += 2 # Chameleon LPS & Null-sig system mtm += self.multi.get_def_mod() assert mtm >= 0, "Negative defensive modifier!" def_factor = 1.0 + (mtm / 10.0) if (printq): print "Target modifier: ", mtm print "Defensive Faction: ", def_factor # Final result dbv *= def_factor if (printq): print "Defensive BV: ", dbv return dbv def off_bv(self, load, printq): """ Get offensive BV """ obv = load.off_bv(self, printq) # Tonnage (physical) weight_factor = 1.0 if (self.load.aes_ra.type == "Arm"): weight_factor += 0.1 if (self.load.aes_la.type == "Arm"): weight_factor += 0.1 if (self.enhancement.is_tsm()): weight_factor *= 1.5 if (printq): print "Weight BV: ", weight_factor * self.weight obv += weight_factor * self.weight # total if (printq): print "Total Base Offensive: ", obv # speed factor off_speed_factor = self.get_off_speed_factor(load, printq) # Final result obv *= off_speed_factor if (printq): print "Offensive BV: ", obv return obv def get_bv(self, load): """ Get the BV of a specific loadout. Use mech.load if not an omni. """ base_bv = self.off_bv(load, False) + self.def_bv(load, False) if (self.cockpit.type == "Small Cockpit" or self.cockpit.type == "Torso-Mounted Cockpit"): batt_val = int(round(base_bv * 0.95)) else: batt_val = int(round(base_bv)) if batt_val != load.batt_val: print ("%s %s%s: %d %d" % (self.name, self.model, load.get_name(), batt_val, load.batt_val)) assert batt_val == load.batt_val, "Error in BV calculation!" return batt_val def get_move_string(self): """ Create a full movement string with TSM and MASC effects """ spd = self.engine.speed + self.load.gear.get_speed_adj() if self.enhancement.is_tsm(): wstr = str(spd) + "[" + str(spd + 1) + "]" else: wstr = str(spd) rspeed = int(ceil(spd * 1.5)) if self.enhancement.is_tsm(): rspeed2 = int(ceil((spd + 1) * 1.5)) rstr = str(rspeed) + "[" + str(rspeed2) + "]" elif self.enhancement.is_masc(): rspeed2 = int(ceil(spd * 2.0)) rstr = str(rspeed) + "[" + str(rspeed2) + "]" else: rstr = str(rspeed) string = ("%s/%s/%d" % (wstr, rstr, self.load.get_jump())) return string def get_rules_level(self, load): """ Return rules level of mech """ r_level = 0 # Mixed tech is advanced rules if self.techbase == "Mixed": r_level = 2 r_level = max(r_level, self.structure.get_rules_level()) r_level = max(r_level, self.engine.get_rules_level()) r_level = max(r_level, self.gyro.get_rules_level()) r_level = max(r_level, self.cockpit.get_rules_level()) r_level = max(r_level, self.enhancement.get_rules_level()) r_level = max(r_level, self.armor.get_rules_level()) r_level = max(r_level, self.multi.get_rules_level()) # Hack -- turrets are advanced rules if load.turret and r_level < 2: r_level = 2 r_level = max(r_level, load.get_rules_level()) return r_level def calculate_cost(self, i): """ Calculate the cost of a mech """ # Structural costs cost = 0 # Cockpit cost += self.cockpit.get_cost() # Life support cost += 50000 # Sensors cost += 2000 * self.weight # Musculature. Handle TSM cost here instead of in enhancement if self.enhancement.is_tsm(): cost += 16000 * self.weight # Primitive mech elif self.engine.etype == "Primitive Fusion Engine": cost += 1000 * self.weight else: cost += 2000 * self.weight # Internal structure cost += self.structure.get_cost() # Acutuators if self.motive == "Biped": # Arms cost += 2 * 100 * self.weight # Upper arms if i.left_arm == "TRUE": cost += 50 * self.weight if i.right_arm == "TRUE": cost += 50 * self.weight if i.left_hand == "TRUE": cost += 80 * self.weight if i.right_hand == "TRUE": cost += 80 * self.weight elif self.motive == "Quad": # Front legs cost += 2 * 150 * self.weight # Upper legs cost += 2 * 80 * self.weight # Lower legs cost += 2 * 120 * self.weight # Feet # Legs/Rear legs cost += 2 * 150 * self.weight # Upper legs cost += 2 * 80 * self.weight # Lower legs cost += 2 * 120 * self.weight # Feet # Engine cost += self.engine.get_cost() # Gyro cost += self.gyro.get_cost() # Jump Jets cost += i.jjets.get_cost() # MASC cost += self.enhancement.get_cost() # Heat Sinks cost += i.heatsinks.get_cost() # Power Amplifiers cost += i.power_amp.get_cost() # Add Tracks here if/when implemented # Armor cost += self.armor.get_cost() # Partial Wing, jump boosters cost += i.partw.get_cost() cost += i.jumpb.get_cost() # Booby trap cost += i.btrap.get_cost() # Multi-slot stuff cost += self.multi.get_cost() # AES cost += i.aes_ra.get_cost() cost += i.aes_la.get_cost() # Hack: Armored components cost += len(i.arm_loc) * 150000 # Hack: Turrets cost += i.gear.tur_weight * 10000 # Gear cost += i.gear.get_cost() # Final calculation cost *= (1.0 + (self.weight / 100.0)) if self.omni == "TRUE": cost *= 1.25 return round(cost)