PyTFall > PyTFall: Bugs and Game balancing

Code review

<< < (7/8) > >>

Xela:
Damn, that devlog thing is useful, just traced a nasty error using it, we should do more of those :)

2 Errors fixed during the next day (Guard Job and guard event with a normal defeat result). Gonna start with shops soon.

rudistoned:

--- Quote from: Xela on June 30, 2013, 03:58:05 AM ---Because it still works, but feel free to remove it completely or turn it into an Error.

--- End quote ---
If the game still works at that point, we should not throw an Exception. However, since your comment states that the else condition should never be reached, reaching it indicates some programming error, so it should log an error message, or at least a warning (devlog.error or devlog.warning). Creating ingame text for a condition that should never be reached seems like wasted effort.

It's no problem of course. I just want to suggest we do it differently in the future  :)

Xela:

--- Quote from: rudistoned on June 30, 2013, 10:05:49 AM ---If the game still works at that point, we should not throw an Exception. However, since your comment states that the else condition should never be reached, reaching it indicates some programming error, so it should log an error message, or at least a warning (devlog.error or devlog.warning). Creating ingame text for a condition that should never be reached seems like wasted effort.

It's no problem of course. I just want to suggest we do it differently in the future  :)

--- End quote ---

Agree with you 110%. Like I've said, when that code was written, I didn't know that [item for item in items] might create a list of items...

rudistoned:
I think I had been programming Python for one or two years when I first read about list comprehension  :D

rudistoned:
Hey guys!


Here is the code I used in Pytherworld to load PyTFalls girl ressources, in case you want a new ressource loader that supports PyTFalls filename-based tagging and can read XMP tags. To use these classes, you need to import the tags package from Pytherworld or Image Tagger in your code. You do not need pyexiv2, because the tags package comes with an included XMP reader in pure python. This means that distributing it with renpy should be easy.  You will also have to adapt these classes a little to your applications needs and environment, of course. Just ask if anything gives you trouble :)



--- Code: ---class PyTFallGirlDataRessourceMap(tags.resload.RessourceMap):
    '''Provides xml ressource files.'''
    def __init__(self, rootdir, picklepath="DEFAULT"):
        tags.resload.RessourceMap.__init__(self, ["data.xml"], rootdir,
                                           picklepath=picklepath)
        # maps pytfall character ids to character name tags
        self.idmap = {}


    def guess_tags(self, relpath):
        '''Returns a list of tags for this file based on relpath.'''
        abspath = os.path.join(self.rootdir, relpath)
        # parse XML
        tree = ET.parse(abspath)
        rootelem = tree.getroot()
        # remember which girls are described here in the tagmap
        nametags = []
        nametags.sort()
        for girlelem in rootelem.iterfind("girl"):
            charnametag = girlelem.attrib["name"]
            nametags.append(charnametag)
            # also rememeber the character folder for each girl
            self.idmap[girlelem.attrib["id"]] = charnametag
        return nametags




class PyTFallImageRessourceMap(tags.resload.ImageRessourceMap):
    '''Provides PyTFall image ressource files.'''
    def __init__(self, patternlist, rootdir, picklepath="DEFAULT"):
        tags.resload.ImageRessourceMap.__init__(self, patternlist, rootdir,
                                                picklepath=picklepath)
        self.girlxml = None
        self.guessmap = {"etiquette": ["learn etiquette"],
                          "dance": ["learn dancing"],
                          "nude.jpg": ["nude"],
                          "rest": ["resting"],
                          "battle_sprite": ["ignore"],
                          "combat": ["ignore"],
                          "date": ["ignore"],
                          "datebeach": ["ignore"],
                          "shop": ["ignore"],
                          "ent": ["ignore"],
                          "Quest": ["ignore"],
                          "quest": ["ignore"],
                          "0quest0": ["ignore"],
                          "0quest1": ["ignore"],
                          "0quest2": ["ignore"],
                          "quest1": ["ignore"],
                          "quest2": ["ignore"],
                          "questsad": ["sad"],
                          "questnormal": ["indifferent"],
                          "questneutral": ["indifferent"],
                          "questhappy": ["happy"],
                          "questangry": ["angry"],
                          "battle": ["ignore"],
                          "portrait.png": ["portrait"],
                          "maid.jpg": ["maid"],
                          "profilesad": ["sad"],
                          "profilehappy": ["happy"],
                          "profileneutral": ["indifferent"],
                          "profileangry": ["angry"],
                          "blowjob": ["+blowjob"],
                          "sex": ["-fuck"],
                          "Sex": ["-fuck"],
                          "anal": ["-anal"],
                          "bdsm": ["-bdsm"],
                          "mast": ["masturbate"],
                          "strip": ["undressing"],
                          "beauty": ["ignore"],
                          "les": ["ignore"],
                          "Les": ["ignore"],
                          "date.jpg": ["ignore"]}
        self.unknown = set()
        # initialize girl data resmap
        ppath = os.path.join(c.PATH.RESDIR, "pytfall", "pytfgirldata.res")
        self.girlxml = PyTFallGirlDataRessourceMap(self.rootdir,
                                                    picklepath=ppath)
        self.girlxml.load()


    def guess_tags(self, relpath):
        '''Returns a list of tags for this file based on its path and XMP tags.


        The filename is converted into a tag by splitting at whitespace and
        treating the first item of the resulting list as the tag.
        The remaining path is split at the path separator and translated into
        tags according to self.guessmap.
        '''
        guessedtags = []
        # split off filename and file extension
        base, fullfn = os.path.split(relpath)
        filename, ext = os.path.splitext(fullfn)
        # split the filename into words and assume the first word is the tag
        firstword = filename.split()[0]
        ##for encoding in ["ascii", "utf-8"]:
            ##try:
                ##firstword = firstword.decode(encoding)
            ##except UnicodeDecodeError:
                ##pass
        ##firstword.encode("utf-8")
        if firstword in self.guessmap:
            guessedtags.extend(self.guessmap[firstword])
        else:
            guessedtags.append(firstword)
            if firstword not in tags.default.known:
                logger.warning("unknown pytfall tag: %s" % firstword)
        # split the path and translate it into tags
        taglist = tags.resload.ImageRessourceMap.guess_tags(self, relpath)
        guessedtags.extend(list(taglist))
        # add tags based on the character
        base = relpath
        charnametag = None
        while base:
            base, dirname = os.path.split(base)
            if dirname in self.girlxml.idmap:
                charnametag = self.girlxml.idmap[dirname]
                guessedtags.append(charnametag)
                break
        if charnametag is None:
            msg = "could not identify charnametag for %s"
            logger.warning(msg % relpath)
        guessedtags.sort()
        # inform if there are untranslated parts
        if c.DEBUG:
            for pathpart in base.split(os.path.sep):
                if (pathpart not in self.guessmap and
                    pathpart not in self.unknown):
                    msg = "No translation for PyTFall path part: %s"
                    logger.info(msg % pathpart)
                    self.unknown.add(pathpart)
        return guessedtags

--- End code ---




Here is one way to instantiate the classes above:



--- Code: --- class PyTFallRessourceNamespace(object):
    '''Makes pytfall ressource loaders accessible via 'c.res.pytfall'.'''
    def __init__(self):
        self.gamedir = os.path.join(c.PATH.PYTFALL, "game")
        # provides images for character screens
        self.girls = None
        # --  initialize  -- #
        rootdir = os.path.join(self.gamedir, "content", "chars")
        # initialize girl image resmap
        picklefile = os.path.join(c.PATH.CACHE, "res_pytfall_girls.res")
        if os.path.exists(picklefile):
            msg = "loaded pytfall girl image metadata from pickled ressource"
            logger.info(msg)
            self.girls = PyTFallImageRessourceMap.from_pickle(picklefile)
        else:
            self.girls = PyTFallImageRessourceMap(["*.jpg", "*.png"], rootdir,
                                                  picklepath=picklefile)
            self.girls.load()
            logger.info("created new pytfall girl image metadata")
            self.girls.to_pickle()

--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version