git @ Cat's Eye Technologies MARYSUE / master src / marysue / state.py
master

Tree @master (Download .tar.gz)

state.py @masterraw · history · blame

import marysue.util as random
from marysue.ast import Properties
from marysue.objects import Object
from marysue.duties import Duty


class State(Properties):
    """State of a character (or other object) at a given point in the story.

    Each State references an Object, which contains the properties of
    that story-object that do not change over the course of the story.

    AST nodes should generally reference a State instead of an Object.
    We have a pass which replaces Objects in ASTs with the State of that
    Object at that particular time (depth-first, i.e. leftmost innermost
    traversal, mapping to time.)  Further passes read and update that
    State on each instantaneous appearance on each Object.

    """
    slots = ('object',
             'is_referent',
             'first_occurrence',
             'torso_costume',
             'legs_costume',
             'feet_costume',
             'hands_costume',
             'head_costume',
             'duties',
             'mood',
             'location',)

    def __init__(self, object, **kwargs):
        assert isinstance(object, Object), repr(object)
        kwargs['object'] = object
        super(State, self).__init__(**kwargs)

    def __getattr__(self, name):
        if name in self.slots:
            return self._attrs[name]
        if not hasattr(self.object, name) and name not in dir(self.object):
            # FIXME should be AttributeError but something catches that
            raise KeyError(name)
        return getattr(self.object, name)

    # Not sure how I feel about these three methods, but, OK
    # (Because State just delegates to Object, and Object doesn't know to do this from inside itself)

    @property
    def definite(self):
        article = self.definite_article
        fnite = self._fnite()
        return article + fnite

    @property
    def indefinite(self):
        article = self.indefinite_article
        fnite = self._fnite()
        if article == 'a 'and fnite[0].upper() in ('A', 'E', 'I', 'O', 'U'):
            article = 'an '
        return article + fnite

    def _fnite(self):
        # helper function
        if not self.first_occurrence:
            if len(self.object.names) == 1:
                return self.object.name
            else:
                r = random.choice(self.object.names[1:])
                return r.replace('{rank}', str(getattr(self.object, 'rank', '')))
        else:
            return self.object.name

    @property
    def pronoun(self):
        if self.is_referent:
            return self.object.pronoun
        else:
            return self.definite

    @property
    def accusative(self):
        if self.is_referent:
            return self.object.accusative
        else:
            return self.definite

    @property
    def possessive(self):
        if self.is_referent:
            return self.object.possessive_pronoun
        else:
            return self.object.possessive

    @property
    def adverb(self):
        assert self.mood, 'mood not assigned to %r' % self
        adverbs = {
            'happy': (
                'courageously', 'obsequiously', 'fawningly', 'blissfully',
                'virtuously', 'happily', 'lightly', 'energetically',
                'laughingly', 'placidly', 'peacefully', 'calmly',
                'enigmatically',
                'strongly', 'firmly',
            ),
            'sad': (
                'drily', 'heavily', 'irritatedly', 'exasperatedly',
                'slowly', 'drably', 'unhappily', 'sadly', 'irksomely',
                'weakly', 'downheartedly', 'grumpily',
                'enigmatically',
            ),
            'angry': (
                'viciously', 'menacingly', 'drily', 'gratingly', 'heavily',
                'threateningly', 'firmly', 'impatiently',
                'icily', 'acidly', 'sternly',
                'emphatically', 'annoyingly', 'irritatedly', 'exasperatedly',
                'outrageously', 'strongly',
                'enigmatically',
                # 'cunningly', 'slyly',
            ),
            'embarrassed': (
                'awkwardly', 'slumblingly', 'coyly', 'slowly',
                'carefully', 'painfully', 'painingly',
                'enigmatically',
                # 'cunningly', 'slyly',
            ),
        }
        return random.choice(adverbs[self.mood])

    @property
    def saids(self):
        return {
            'happy': (
                'said', 'stated', 'chirped', 'smiled',
                'sighed', 'breathed', 'whispered', 'giggled',
                'drawled',
            ),
            'sad': (
                'said', 'groaned', 'muttered', 'intoned', 'droned',
                'gasped', 'gulped', 'mumbled', 'bleated',
            ),
            'angry': (
                'said', 'groaned', 'muttered',
                'intoned', 'barked', 'splurted',
                'bellowed', 'shouted', 'yelled', 'raged',
            ),
            'embarrassed': (
                'said', 'groaned', 'muttered',
                'whispered', 'mumbled',
                'gasped', 'gulped', 'sighed', 'breathed',
            ),
        }

    @property
    def said(self):
        assert self.mood, 'mood not assigned to %r' % self
        return random.choice(self.saids[self.mood])

    @property
    def shouteds(self):
        return {
            'happy': (
                'exclaimed', 'yelled', 'squealed', 'yelped', 'shouted',
                'cried',
            ),
            'sad': (
                'exclaimed', 'yelped', 'shouted',
                'gasped', 'gulped', 'screeched', 'cried',
            ),
            'angry': (
                'yelled', 'screeched', 'shouted',
                'screamed', 'bellowed', 'barked',
            ),
            'embarrassed': (
                'yelled', 'yelped', 'screamed', 'shouted',
                'gasped', 'gulped', 'screeched', 'cried',
            ),
        }

    @property
    def shouted(self):
        assert self.mood, 'mood not assigned to %r' % self
        return random.choice(self.shouteds[self.mood])

    @property
    def emoted(self):
        assert self.mood, 'mood not assigned to %r' % self
        emoteds = {
            'happy': (
                'smiled', 'whistled', 'grinned', 'beamed', 'winked',
            ),
            'sad': (
                'frowned', 'gasped', 'blinked', 'pouted',
            ),
            'angry': (
                'frowned', 'grimaced', 'blinked',
            ),
            'embarrassed': (
                'blushed', 'frowned', 'looked away',
            ),
        }
        return random.choice(emoteds[self.mood])

    @property
    def pick_duty(self):
        if self.duties:
            return random.choice(self.duties)
        else:
            return Duty(names=('uphold the code of the Star Fighters',))