Example #1
0
    def toWeapon(self) -> weapon.Weapon:
        if self.baseweapon is not None:
            retval = weapon.get(self.baseweapon)
        else:
            retval = weapon.Weapon(None)

        for attrib, value in self.setcmds:
            setattr(retval, attrib, value)

        retval.additionalmodcmds += f"\n-- Generated from NewWeapon {self.name}\n"
        retval.additionalmodcmds += "\n".join(self.rawcmds)
        retval.additionalmodcmds += "\n"
        retval.uniqueid = f"newweapon-{self.name}"
        retval.newweapon = self
        retval.isnewweapon = True

        return retval
Example #2
0
    def from_line(line):
        global descriptioncache
        self = UnitInBaseDataFinder()
        self.line = line
        self.params = ["id", "origid", "weapons", "descr", "uniqueid"]
        id = int(line["id"])
        self.origid = id
        self.id = id
        for k in line.keys():
            try:
                val = int(line[k])
            except:
                val = line[k]
            if (val is None or val == "") and k in _badkeys:
                continue
            if val is None: val = -1
            if val == "": val = -1
            setattr(self, k, val)
            self.params.append(k)
        self.weapons = []
        for x in range(1, 8):
            if getattr(self, f"wpn{x}") > 0:
                self.weapons.append(weapon.get(getattr(self, f"wpn{x}")))

        self.descr = ""
        if self.id in descriptioncache:
            self.descr = copy(descriptioncache[self.id])
        else:
            fp = os.path.join("./unitdescr",
                              f"{str(self.origid).zfill(4)}.txt")
            if os.path.isfile(fp):
                with open(fp, "r", encoding="utf-8") as f:
                    self.descr = f.read()
            descriptioncache[self.id] = copy(self.descr)
        self.uniqueid = f"vanilla-{self.id}"
        if self.mapmove < 6:
            self.mapmove = self.mapmove * 6 + 2
            if self.flying > 0:
                self.mapmove += 6
            if self.slave > 0:
                self.mapmove -= 2

        return self
Example #3
0
    def toUnitBaseData(self) -> unitinbasedatafinder.UnitInBaseDataFinder:
        #self._init()
        if self.baseunit is not None:
            retval = unitinbasedatafinder.get(self.baseunit)
            if self.clearweapons != 0:
                retval.weapons = []
        else:
            retval = unitinbasedatafinder.UnitInBaseDataFinder()

        for wpnid in self.addweapons:
            retval.weapons.append(weapon.get(wpnid))

        for attrib, value in self.setcmds:
            setattr(retval, attrib, value)

        retval.additionalmodcmds += f"\n-- Generated from NewUnit {self.name}\n"
        retval.additionalmodcmds += "\n".join(self.rawcmds)
        retval.additionalmodcmds += "\n"
        retval.uniqueid = f"newunit-{self.name}"

        return retval
Example #4
0
    def applytounit(self,
                    spell,
                    u,
                    extrashapechain=None,
                    additionals_firstshape=None,
                    spelleffect=None,
                    actualpowerlvl=None,
                    secondaryeffect=None):
        """Apply this effect to the given unit object, returning mod code for the new unit.

                spell can be None. If given, spell.damage is set to the correct unit ID for the new unit.
                extrashapechain should not be set manually as it is used to track wounded shapes and make them all
                join together neatly

                additionals_firstshape should be a dict of {modcommand:value} that is appended to the first shape ONLY.
                So far this is used for things like adding units to montags and giving them a montagweight.
                The modcommand given should INCLUDE A HASH.
                """
        if extrashapechain is None:
            extrashapechain = {}
            self.lastunitAIScore = 0

        u.descr += " " + self.descr
        u.descr = u.descr.replace("CREATURE", u.name)
        u.descr = naming.parsestring(u.descr)
        u.name = self.nameprefix + " " + u.name
        u.name = u.name.strip()
        self.lastunitname = u.name

        out = ""

        # Weapon mod
        wpnmod = utils.weaponmods[self.weaponmod]
        wpnreplacements, wpnoutput = wpnmod.apply(u)
        for wpn in u.weapons:
            if wpn.uniqueid in wpnreplacements:
                wpn.origid = wpnreplacements[wpn.uniqueid]
        out += wpnoutput

        # Event set derived attributes, for things like summoning magicgen creatures or actual event set things
        if self.eventset != "" and self.attributeforrandomunit != "":
            realeventset = utils.eventsets[self.eventset]
            # actualpowerlvl is 0 in all current cases - because commander spells do not have any research level
            # scaling that is not done through secondary effects
            eventsetdata = realeventset.formatdata(spelleffect, spell, 0, None,
                                                   actualpowerlvl)
            if eventsetdata is None:
                return None
            out = eventsetdata + "\n" + out
            setattr(u, self.attributeforrandomunit, realeventset.lastunitid)
            u.additionalmodcmds += f"#{self.attributeforrandomunit} {realeventset.lastunitid}\n"

        if utils.MONSTER_ID >= 9000:
            raise ValueError(
                "New Monster ID is too high for Dominions! Consider changing starting ID or lowering montag sizes."
            )

        out += f"-- Modified unit {u.uniqueid} with unitmod {self.name}\n"
        out += f"#newmonster {utils.MONSTER_ID}\n"
        # Update the spell to summon the new creature
        # needless to say, don't do this if the current monster is a secondshape something caused by running in recursive mode
        # or the spell will be left summoning the last thing in the secondshape chain
        if len(extrashapechain) == 0:
            if spell is not None and spell.effect % 1000 in [
                    1, 21, 37, 38, 43, 50, 89, 93, 119, 137, 54, 130, 62
            ]:
                print(
                    f"unitmod {self.name}: is first pass, fixed spell.damage -> {utils.MONSTER_ID}"
                )
                spell.damage = utils.MONSTER_ID
            else:
                self.lastparentid = utils.MONSTER_ID
        utils.MONSTER_ID += 1
        if u.origid is not None:
            out += f"#copystats {u.origid}\n"
            if u.newunit is None or u.newunit.spr1 is None:
                out += f"#copyspr {u.origid}\n"
            out += "#descr {}{}{}\n".format('"', u.descr, '"')
            out += "#name {}{}{}\n".format('"', u.name, '"')
            out += f"#clearweapons\n"

        # New unit stuff should go here
        out += u.additionalmodcmds + "\n"

        if len(self.addweapons) > 0:
            for wpn in self.addweapons:
                #out += f"#weapon {wpn}\n"
                u.weapons.append(weapon.get(wpn))

        for wpn in u.weapons:
            out += f"#weapon {wpn.origid}\n"

        # Disable transformation
        if hasattr(u, "transformation"):
            if u.transformation != 0:
                out += "#transformation 0\n"

        for param in self.params:
            if hasattr(self, param):
                paramv = getattr(self, param)
                if paramv != 0:
                    if not hasattr(u, param):
                        print(
                            f"Unit {u.name} didn't have param {param} when affected by unitmod {self.name}, assumed 0"
                        )
                        setattr(u, param, 0)
                    newparamval = getattr(u, param) + paramv

                    # do not mess with certain values of morale, they should be done with set commands only
                    if param == "mor":
                        oldval = getattr(u, param)
                        if oldval == 30:
                            newparamval = 30
                        if oldval == 50:
                            newparamval = 50

                    setattr(u, param, newparamval)
                    modcmd = flags_to_mod_cmds.get(param, param)

                    if modcmd not in argless_cmds:
                        out += f"#{modcmd} {newparamval}\n"
                    else:
                        out += f"#{modcmd}\n"

        for param, val in self.setcommands:
            modcmd = flags_to_mod_cmds.get(param, param)
            if modcmd not in argless_cmds:
                if isinstance(val, str):
                    out += "#{} {}{}{}\n".format(modcmd, '"', val, '"')
                else:
                    out += f"#{modcmd} {val}\n"
            else:
                out += f"#{modcmd}\n"

        for param, val in self.multcommands:
            paramv = getattr(u, param)
            newparamval = int(val * paramv)
            setattr(u, param, newparamval)
            modcmd = flags_to_mod_cmds.get(param, param)
            out += f"#{modcmd} {newparamval}\n"

        aiscore = u.calcSummonAIScore()
        self.lastunitAIScore += aiscore
        print(
            f"AIscore for this unit is {aiscore}, total now {self.lastunitAIScore}"
        )

        secondshapeextra = ""
        # Second shape needs to propagate
        for x in [
                "shapechange", "firstshape", "secondshape", "secondtmpshape",
                "forestshape", "plainshape", "foreignshape", "homeshape",
                "domshape", "notdomshape", "springshape", "summershape",
                "autumnshape", "wintershape", "landshape", "watershape"
        ]:
            if hasattr(u, x):
                uid = getattr(u, x)
                oldscore = copy(self.lastunitAIScore)
                if uid not in extrashapechain and uid > 0:
                    extrashapechain[uid] = copy(utils.MONSTER_ID)
                    print(
                        f"UID {uid} is a {x} of {u.name}, applying to that too..."
                    )
                    secondshapeextra += self.applytounit(
                        spell,
                        unitinbasedatafinder.get(uid),
                        extrashapechain,
                        spelleffect=spelleffect,
                        actualpowerlvl=actualpowerlvl,
                        secondaryeffect=secondaryeffect)
                if uid in extrashapechain and uid > 0:
                    # update this creature's secondshape or whatever with the new creature
                    out += f"#{x} {extrashapechain[uid]}\n"
                # only secondshape counts towards AI scores
                if x != "secondshape":
                    self.lastunitAIScore = oldscore

        if additionals_firstshape is not None:
            for modcmd, val in additionals_firstshape.items():
                out += f"{modcmd} {val}\n"

        # Special case: Do nothing should firstshape to the original unit
        # This makes montags built with Do Nothing-modified units quickly transform to their normal version
        # which means double click correctly selects all of them amongst other things

        # ...but not if this is a newunit, as u.id will instead be undefined or whatever we copystats-ed from originally
        if self.name == "Do Nothing" and u.newunit is None:
            out += f"#firstshape {u.id}\n"
        if u.newunit is not None:
            if u.newunit.spr1 is not None:
                utils.spritedependencies.add(u.newunit.spr1)
            if u.newunit.spr2 is not None:
                utils.spritedependencies.add(u.newunit.spr2)

        out += "#end\n\n"

        out += secondshapeextra

        return out