Пример #1
0
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