def __init__(self, load, mech, batt_val, prod_era, equip, cost): self.weight = mech.weight # Save weight just in case self.artemis4 = load.attributes["fcsa4"].value self.artemis5 = load.attributes["fcsa5"].value self.apollo = load.attributes["fcsapollo"].value self.cost = cost self.unit = mech # Reference to parent # Create a container for special abilities # ES, SEAL, SOA, SRCH is always available for mechs # Combat Vehicles gets SRCH if mech.type == "BM": self.specials = {"ES": 1, "SEAL": 1, "SOA": 1, "SRCH": 1} elif mech.type == "CV": self.specials = {"SRCH": 1} # Get source self.source = get_child_data(load, "source") # Get Clan CASE # Note that there is currently a bug in combat vehicles regarding # Clan CASE. if mech.type == "BM": clanc = get_child_data(load, "clancase") else: clanc = "FALSE" # Get actuator status for act in load.getElementsByTagName("actuators"): self.left_hand = act.attributes["lh"].value self.left_arm = act.attributes["lla"].value self.right_hand = act.attributes["rh"].value self.right_arm = act.attributes["rla"].value self.batt_val = batt_val # Set to zero things that might not get defined otherwise self.heatsinks = Heatsinks(None, self) self.jjets = JumpJets(None, mech.weight) self.partw = PartialWing(mech.weight, False, 2) # Assume not mixed tech self.mixed = False for rll in load.getElementsByTagName("techbase"): if gettext(rll.childNodes) == "Mixed": self.mixed = True # Get Actuator Enhancement System self.aes_ra = AES(mech.weight, mech.motive, "None") self.aes_la = AES(mech.weight, mech.motive, "None") for aes in load.getElementsByTagName("arm_aes"): if aes.attributes["location"].value == "LA": self.aes_la = AES(mech.weight, mech.motive, "Arm") elif aes.attributes["location"].value == "RA": self.aes_ra = AES(mech.weight, mech.motive, "Arm") # Get jump booster jumpb = 0 for jbo in load.getElementsByTagName("jumpbooster"): jumpb = int(jbo.attributes["mp"].value) self.jumpb = JumpBoosters(mech.weight, jumpb) # Get Armored locations self.arm_loc = [] self.arm_gyro = False self.armored = False for arm in load.getElementsByTagName("armored_locations"): for loc in arm.getElementsByTagName("location"): index = int(loc.attributes["index"].value) location = gettext(loc.childNodes) self.arm_loc.append((location, index)) self.armored = True # Armored Gyro if location == "CT" and index == 3: self.arm_gyro = True self.prod_era = prod_era # Get booby trap booby = False for bob in load.getElementsByTagName("boobytrap"): booby = True self.btrap = BoobyTrap(mech.weight, booby) # Hack: Get turret self.turret = False for tur in load.getElementsByTagName("turret"): self.turret = True self.gear = Gear(mech, self.artemis4, self.artemis5, self.apollo, equip, clanc) # Add Power Amplifiers if self.unit.engine.etype == "I.C.E. Engine" or self.unit.engine.etype == "No Engine": self.power_amp = PowerAmp(self, self.gear.weaponlist.ene_weight) else: self.power_amp = PowerAmp(self, 0.0) self.build_special()
class Load: """ Parent class for omni loadouts """ def __init__(self, load, mech, batt_val, prod_era, equip, cost): self.weight = mech.weight # Save weight just in case self.artemis4 = load.attributes["fcsa4"].value self.artemis5 = load.attributes["fcsa5"].value self.apollo = load.attributes["fcsapollo"].value self.cost = cost self.unit = mech # Reference to parent # Create a container for special abilities # ES, SEAL, SOA, SRCH is always available for mechs # Combat Vehicles gets SRCH if mech.type == "BM": self.specials = {"ES": 1, "SEAL": 1, "SOA": 1, "SRCH": 1} elif mech.type == "CV": self.specials = {"SRCH": 1} # Get source self.source = get_child_data(load, "source") # Get Clan CASE # Note that there is currently a bug in combat vehicles regarding # Clan CASE. if mech.type == "BM": clanc = get_child_data(load, "clancase") else: clanc = "FALSE" # Get actuator status for act in load.getElementsByTagName("actuators"): self.left_hand = act.attributes["lh"].value self.left_arm = act.attributes["lla"].value self.right_hand = act.attributes["rh"].value self.right_arm = act.attributes["rla"].value self.batt_val = batt_val # Set to zero things that might not get defined otherwise self.heatsinks = Heatsinks(None, self) self.jjets = JumpJets(None, mech.weight) self.partw = PartialWing(mech.weight, False, 2) # Assume not mixed tech self.mixed = False for rll in load.getElementsByTagName("techbase"): if gettext(rll.childNodes) == "Mixed": self.mixed = True # Get Actuator Enhancement System self.aes_ra = AES(mech.weight, mech.motive, "None") self.aes_la = AES(mech.weight, mech.motive, "None") for aes in load.getElementsByTagName("arm_aes"): if aes.attributes["location"].value == "LA": self.aes_la = AES(mech.weight, mech.motive, "Arm") elif aes.attributes["location"].value == "RA": self.aes_ra = AES(mech.weight, mech.motive, "Arm") # Get jump booster jumpb = 0 for jbo in load.getElementsByTagName("jumpbooster"): jumpb = int(jbo.attributes["mp"].value) self.jumpb = JumpBoosters(mech.weight, jumpb) # Get Armored locations self.arm_loc = [] self.arm_gyro = False self.armored = False for arm in load.getElementsByTagName("armored_locations"): for loc in arm.getElementsByTagName("location"): index = int(loc.attributes["index"].value) location = gettext(loc.childNodes) self.arm_loc.append((location, index)) self.armored = True # Armored Gyro if location == "CT" and index == 3: self.arm_gyro = True self.prod_era = prod_era # Get booby trap booby = False for bob in load.getElementsByTagName("boobytrap"): booby = True self.btrap = BoobyTrap(mech.weight, booby) # Hack: Get turret self.turret = False for tur in load.getElementsByTagName("turret"): self.turret = True self.gear = Gear(mech, self.artemis4, self.artemis5, self.apollo, equip, clanc) # Add Power Amplifiers if self.unit.engine.etype == "I.C.E. Engine" or self.unit.engine.etype == "No Engine": self.power_amp = PowerAmp(self, self.gear.weaponlist.ene_weight) else: self.power_amp = PowerAmp(self, 0.0) self.build_special() def build_special(self): """ Add special abilities to list """ # Scan equipment for equip in self.gear.equiplist.list: if equip.count > 0 and equip.name == "C3 Computer (Master)": self.specials["C3M"] = equip.count self.specials["TAG"] = 1 if equip.count > 0 and equip.name == "C3 Boosted Computer (Master)": self.specials["C3BSM"] = equip.count self.specials["TAG"] = 1 if equip.count > 0 and equip.name == "Improved C3 Computer": self.specials["C3I"] = 1 if equip.count > 0 and equip.name == "C3 Computer (Slave)": self.specials["C3S"] = 1 if equip.count > 0 and equip.name == "C3 Boosted Computer (Slave)": self.specials["C3BSS"] = 1 if equip.count > 0 and equip.name == "TAG": self.specials["TAG"] = 1 if equip.count > 0 and equip.name == "Light TAG": self.specials["LTAG"] = 1 if equip.count > 0 and equip.name == "Watchdog CEWS": self.specials["WAT"] = 1 if equip.count > 0 and ( equip.name == "Guardian ECM Suite" or equip.name == "ECM Suite" or equip.name == "Electronic Warfare Equipment" ): self.specials["ECM"] = 1 if equip.count > 0 and equip.name == "Angel ECM": self.specials["AECM"] = 1 if equip.count > 0 and equip.name == "Bloodhound Active Probe": self.specials["BH"] = 1 self.specials["RCN"] = 1 if equip.count > 0 and (equip.name == "Beagle Active Probe" or equip.name == "Active Probe"): self.specials["PRB"] = 1 self.specials["RCN"] = 1 if equip.count > 0 and equip.name == "Light Active Probe": self.specials["LPRB"] = 1 self.specials["RCN"] = 1 if equip.count > 0 and equip.name == "Remote Sensor Dispenser": self.specials["RSD"] = equip.count self.specials["RCN"] = 1 if equip.count > 0 and equip.name == "C3 Remote Sensor Launcher": self.specials["C3RS"] = 1 if equip.count > 0 and ( equip.name == "(IS) Anti-Missile System" or equip.name == "(CL) Anti-Missile System" or equip.name == "(IS) Laser Anti-Missile System" or equip.name == "(CL) Laser Anti-Missile System" ): self.specials["AMS"] = 1 # Scan weapons for weap in self.gear.weaponlist.list.itervalues(): if weap.count > 0 and (weap.name == "(IS) Narc Missile Beacon" or weap.name == "(CL) Narc Missile Beacon"): self.specials["SNARC"] = weap.count if weap.count > 0 and (weap.name == "(IS) iNarc Launcher"): self.specials["INARC"] = weap.count if weap.count > 0 and weap.name == "(IS) BattleMech Taser": self.specials["MTAS"] = weap.count if weap.count > 0 and weap.name == "(IS) Arrow IV Missile": self.specials["ARTAIS"] = weap.count if weap.count > 0 and weap.name == "(CL) Arrow IV Missile": self.specials["ARTAC"] = weap.count if weap.count > 0 and weap.name == "(IS) Sniper": self.specials["ARTS"] = weap.count # Is this one really correct? Does Artillery Cannons count? if weap.count > 0 and weap.name == "Long Tom Artillery Cannon": self.specials["ARTLTC"] = weap.count def get_name(self): """ Return the name of the Loadout, if any """ raise NotImplementedError def get_rules_level(self): """ Return rules level of loadout """ r_level = 0 # Mixed Tech is advanced rules if self.mixed: r_level = 2 r_level = max(r_level, self.gear.get_rules_level()) r_level = max(r_level, self.heatsinks.get_rules_level()) r_level = max(r_level, self.jjets.get_rules_level()) r_level = max(r_level, self.partw.get_rules_level()) r_level = max(r_level, self.jumpb.get_rules_level()) r_level = max(r_level, self.btrap.get_rules_level()) r_level = max(r_level, self.aes_ra.get_rules_level()) r_level = max(r_level, self.aes_la.get_rules_level()) r_level = max(r_level, self.power_amp.get_rules_level()) # Hack: Armored location if self.armored == True and r_level < 2: r_level = 2 return r_level def get_sink(self): """ Get heatsinking capability """ sink = self.heatsinks.get_sink() # coolant pods if self.gear.coolant > 0: cool = ceil(self.heatsinks.number * (float(self.gear.coolant) / 5.0)) if cool > (self.heatsinks.number * 2): cool = self.heatsinks.number * 2 sink += cool # Partial Wing if self.partw.has_wing(): sink += 3 return int(sink) def get_prod_era(self): """ Get production era """ return self.prod_era def get_jump(self): """ Get max jumping range """ # Ordinary jump-jets jmp = self.jjets.get_jump() # Handle partial wing if jmp and self.partw.has_wing(): if self.weight >= 60: jmp += 1 else: jmp += 2 # Mechanical jump boosters jump = max(jmp, self.jumpb.get_jump()) return jump def get_move_heat(self, mech): """ Get maximum heat produced by movement. """ run_heat = 2 if mech.engine.etype == "XXL Engine": run_heat = 6 move_heat = max(run_heat, self.jjets.get_heat(mech)) return move_heat def get_def_bv(self, mech): """ Get defensive equipment BV """ dbv = self.gear.get_def_bv() # Track things left arm_loc = self.arm_loc[:] # Deal with armored components for i in self.arm_loc: # Gyros, BV calculated elsewhere for j in mech.gyro.get_slots(): if not cmp(i, j): arm_loc.remove(i) # Engines for j in mech.engine.get_slots(): if not cmp(i, j): dbv += 5 arm_loc.remove(i) # Cockpits for j in mech.cockpit.get_slots(): if not cmp(i, j): dbv += 5 arm_loc.remove(i) # Actuators act_locations = [ ("LA", 0), ("LA", 1), ("RA", 0), ("RA", 1), ("LL", 0), ("LL", 1), ("LL", 2), ("LL", 3), ("RL", 0), ("RL", 1), ("RL", 2), ("RL", 3), ] if self.left_arm == "TRUE": act_locations.append(("LA", 2)) if self.left_hand == "TRUE": act_locations.append(("LA", 3)) if self.right_arm == "TRUE": act_locations.append(("RA", 2)) if self.right_hand == "TRUE": act_locations.append(("RA", 3)) for j in act_locations: if not cmp(i, j): dbv += 5 arm_loc.remove(i) if arm_loc: print "Unknown armored items left: ", arm_loc raise NotImplementedError return dbv def off_bv(self, mech, printq): """ Get offensive weapon and ammo BV """ obv = 0.0 bwbr = 0.0 heat = 0 ammo_bv = 0.0 heat_eff = 6 + self.get_sink() - self.get_move_heat(mech) if printq: print "Heat Efficiency", heat_eff # Check for weapon BV flip flip = self.gear.check_weapon_bv_flip() w_list = [] # Weapons for weap in self.gear.weaponlist.list.itervalues(): if weap.count > 0: i = weap.count left_arm = weap.count_la right_arm = weap.count_ra if flip and (i - weap.count_la - weap.count_ra - weap.count_tur > 0): batt_val = weap.get_bv(self.gear.tarcomp) / 2.0 else: batt_val = weap.get_bv(self.gear.tarcomp) # Handle AES if left_arm > 0 and self.aes_la.type == "Arm": batt_val *= 1.5 left_arm -= 1 elif right_arm > 0 and self.aes_ra.type == "Arm": batt_val *= 1.5 right_arm -= 1 while i: w_list.append((batt_val, weap.get_heat(), weap.name)) i -= 1 # Rear-facing weapons counts as half if weap.countrear > 0: i = weap.countrear if flip: batt_val = weap.get_bv(self.gear.tarcomp) else: batt_val = weap.get_bv(self.gear.tarcomp) / 2.0 while i: w_list.append((batt_val, weap.get_heat(), weap.name)) i -= 1 # Count possible Ammo BV ammo_bv += weap.get_ammo_bv() # Physical weapons for weap in self.gear.physicallist.list: # Only offensive physical gear if weap.count > 0 and weap.get_bv() > 0: i = weap.count left_arm = weap.count_la right_arm = weap.count_ra batt_val = weap.get_bv() # Handle AES if left_arm > 0 and self.aes_la.type == "Arm": batt_val *= 1.5 left_arm -= 1 elif right_arm > 0 and self.aes_ra.type == "Arm": batt_val *= 1.5 right_arm -= 1 while i: w_list.append((batt_val, weap.heat, weap.name)) i -= 1 # Sort list, from largest BV to smallest, # and from lowest heat to highest w_list.sort(key=itemgetter(1)) # secondary by heat w_list.sort(key=itemgetter(0), reverse=True) # primary by BV # Calculate weapon BV over = 0 for i in w_list: if over > 0 and i[1] > 0: bwbr += i[0] / 2.0 heat += i[1] if printq: print "Over-heat" else: bwbr += i[0] heat += i[1] # We have to much heat, halve future weapon BV if heat >= heat_eff and mech.type != "CV": over = 1 if printq: print i if printq: print "BWBR", bwbr obv = bwbr # Ammo obv += ammo_bv if printq: print "Ammo BV: ", ammo_bv # Non-heat gear equip_bv = 0 for equip in self.gear.equiplist.list: # Only offensive physical gear if equip.count > 0 and equip.off_bv[0] > 0: bv_gear = equip.off_bv[0] * equip.count equip_bv += bv_gear # Handle C3 ammo (and possible other ammo) if equip.off_bv[1] > 0 and equip.ammocount > 0: bv_ammo = equip.off_bv[1] * equip.ammo_ton # Disallow ammo BV to be greater than that of # the system itself if bv_ammo > bv_gear: bv_ammo = bv_gear equip_bv += bv_ammo obv += equip_bv if printq: print "Equipment BV: ", equip_bv return obv