Commits

Anonymous committed 04d7698

cleanup work

Comments (0)

Files changed (69)

lib/anyrpg.py

-#!/usr/bin/env python
-# encoding: utf-8
-
-"""AnyRPG - Basic functions and classes for simple RPG scripting modules.
-
-It contains the basic functions any RPG scripting module which wants to be compatible with TextRPG stories needs to provide. 
-
-TODO: Add doctests, since it begins to become more complex... 
-
-Plans: 
-    - Simple to use functions in easy to read scriptfiles in the style of the ministory file. 
-    - char.compete(other, skill_name) -> See who wins and by how much. 
-
-Ideas: 
-    - Lazy loading modules, to be able to print stuff at once without having to print before the imports.
-    - Add getting experience for groups and show the chars together (only one experience header instead of one per char). 
-
-
-Basic design principles for the scripting language: 
-    
-    - The action is character centered wherever possible and useful. 
-       -> char.say(text) instead of dialog(char, text)
-    
-    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
-       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
-    
-    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
-       -> save([char1, char2]) instead of char1.save() char2.save()
-    
-    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
-       -> For example AI.choose_the_way(players_answer) or music.action()
-    
-    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story. 
-       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
-    
-    - Actions should be written as verb_noun or simply verb. 
-       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
-     
-    - In the story function, an action is a parameter of the story. 
-       -> story(switch_background_image="bg_image.png")
-     
-
-Design:
-    - revert: story() is a function, but should be heavily overloaded, so it gets 
-used for any kind of interacion with the setting. -> story(background="...", 
-show_image="...", clear_images=True, background_musi="...", play_sound="...", ...)
-      Reason: The story is the central background. 
-      It creates the setting, just like an exposition. 
-      So it can be treated in a special way. 
-      This means: Doing it this way makes the scripts appear more natural (to me). 
-      Also this allows story() to rearrange the order of passed arguments, if all get passed in one step -> a simpler way to say "new scene". 
-
-
-This (and other) code can be found at U{http://freehg.org/ArneBab/textrpg}
-
-Doctests: 
-    >>> story_helper = Story()
-    >>> story_helper.story("The flow changes", autoscroll=True)
-    The flow changes
-    >>> story_helper.story("", autoscroll=True)
-    <BLANKLINE>
-
-"""
-
-# Structure for the metadata inspired by Fufezan: 
-# -> http://fufezan.net/python.php
-__copyright__ = """ 
-  TextRPG - Simple TextRPG module built on top of the 1d6 RPG library.
-  -> http://freehg.org/ArneBab/textrpg
------------------------------------------------------------------ 
-© 2008 - 2008 Copyright by Arne Babenhauserheide(arne_bab@web.de) 
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 3 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-  MA 02110-1301 USA
-
-""" 
-__author__    = 'Arne Babenhauserheide' 
-# __date__      = '7th March 2007' 
-__url__       = 'http://rpg-1d6.sf.net' 
-
-__version__   = '0.1' 
-
-from textrpg_1d6 import Char as ews_char
-from time import sleep # for autoscrolling
-
-### Classes ###
-
-class UserInteraction(object): 
-    """Basic user interaction: Showing and asking things."""
-    def __init__(self, *args, **kwds): 
-        super(UserInteraction, self).__init__(*args, **kwds)
-        
-    def ask(self, question=None, *args, **kwds): 
-        """Ask a question.
-        
-        Note: Not console based implementations will want to overwrite this. """
-        if question is not None: 
-            return raw_input(_(question) + " ")
-    
-    def diag(self, data, localize=True, autoscroll=False, *args, **kwds):
-        if localize: 
-            text = _(data)
-        else: text = data 
-    
-        if not autoscroll: 
-            raw_input(text)
-        else: 
-            print text
-            # First sleep 1/10th second. This ensures that the text gets shown before sleeping.
-            sleep(0.1)
-            sleep((len(text) - 1)*0.1)
-
-class Dialogs(object): 
-    """Basic dialogs. 
-    
-    A dialog never interacts with the user directly, it just provides template for otehr code.
-    
-    If you want a specific interaction, write a function in UserInteraction, or split the dialog and interact via the higher classes (i.e. Char or Story)."""
-    def __init__(self, *args, **kwds): 
-        super(Dialogs, self).__init__(*args, **kwds)
-    
-    def get_experience(self, chars, amount=0):
-        """Show the experience the chars get and what they do with it."""
-        text = ""
-        print self.get_experience_header(chars=chars, amount=amount)
-            
-        # Info text for each char. 
-        for i in chars: 
-            result = i.incremental_upgrade(amount=1)
-            if result: 
-                text += result 
-            
-        # Dialog footer. 
-        text += self.get_experience_footer(chars, amount=amount)
-        return text
-    
-    def get_experience_header(self, chars, amount=0):
-        """@return: The header line of the experience dialog."""
-        scribble = ""
-        if len(chars) == 1: 
-            scribble += "\n***experience of " + chars[0].name + "***\n"
-            scribble += chars[0].name + " got " + str(amount) + " experience."
-        else: 
-            scribble += "\n***experience***\n"
-            scribble += "The characters got " + str(amount) + " experience."
-        return scribble
-    
-    def get_experience_footer(self, chars, amount=0):
-        """@return: The header line of the experience dialog."""
-        return "***/experience***\n"
-    
-    
-    def upgrade_info(self, char, amount): 
-        """Return the effects of improving the char by the given amount of points/Strichen."""
-        upgrade = char.upgrade(amount)
-        item_name = " ".join(upgrade[0].items()[0][0])
-        old_value = upgrade[0].items()[0][1]["Zahlenwert"] 
-        new_value = upgrade[1].items()[0][1]["Zahlenwert"]
-        if old_value < new_value:
-            return char.name + " raised " + item_name + " from " + str(old_value) + " to " + str(new_value) + "\n"
-        else: 
-            return False
-
-
-class Char(ews_char, UserInteraction, Dialogs):
-    """A Char is any character in the game, those from the player as well as others."""
-    def __init__(self, template=False, *args, **kwds): 
-        """A Char is any character in the game, those from the player as well as others."""
-        super(Char, self).__init__(template=template, *args, **kwds)
-        self.battle_diff_treshold = 4 #: The treshold of the char below which no hit is scored. 
-    
-    def say(self, data): 
-        """Say something -> Show that the char says it."""
-        data = _(data)
-        for i in data.split("\n"): 
-            self.diag(self.name + ': ' + i, localize=False)
-    
-    def act(self, data): 
-        """Do something -> Show that the char does it in the style "<name> walks away.".
-        
-        Usage: 
-            >>> char = Char(source="tag:1w6.org,2008:Mins")
-            >>> char.act("walks away.")
-            Mins walks away.
-        """
-        data = _(data)
-        for i in data.split("\n"): 
-            self.diag(self.name + ' ' + i, localize=False)
-        
-    def compete_skill(self, other, skill_name, self_mods=[], other_mods=[]): 
-        """Compete with the other char in the specified skill. 
-        
-        @return If we won and by how much: (won, diff). Diff is always >=0. 
-        """
-        my_result = self.roll(self.get_effective_skill_value(skill_name, related_skills=[], related_attributes=[]), mods=self_mods)
-        other_result = other.roll(other.get_effective_skill_value(skill_name, related_skills=[], related_attributes=[]), mods=other_mods)
-        return my_result > other_result, abs(my_result - other_result)
-    
-    def get_exp(self, amount=0): 
-        """Get experience and show it."""
-        for i in self.get_experience([self], amount).splitlines(): 
-            self.diag(i)
-    
-    def incremental_upgrade(self, amount=0): 
-        # Upgrade in single point steps, so the experience gets spread a bit. 
-        # if it's less than two points, use it completely. 
-        if amount <= 2: 
-            text = self.upgrade_info(self, amount)
-        # If it's more than one point, spread all but one in single points 
-        # and at last improve by 1 plus the remaining fraction. 
-        # With this, no value gets less than one point/Strich 
-        # (no use in spreading points which can only give an increase by pure chance). 
-        else: 
-            text = ""
-            for j in range(int(amount) -1): 
-                text += self.upgrade_info(self, 1)
-            text += self.upgrade_info(self, amount - int(amount) + 1)
-        return text
-    
-    def battle(self, other): 
-        """Fight a deadly battle."""
-        return self.fight_while_standing(self, other)
-    
-    def fight_while_standing(self, me, other):
-        '''Fight as long as both characters are still active.
-        
-        Plans: 
-            - TODO: Select fight styles, when you attack as well as when the other attacks. 
-        '''
-        
-        # Show the battle status of both chars. 
-        self.diag(self.battle_info(me, other))
-        
-        # Ask the player which action to take.        
-        self.diag(other.name + ' comes closer.')
-        won, injuries_self, injuries_other = self.select_battle_action(me, other)
-        
-        self.diag(self.battle_round_result(me, other, won, injuries_self, injuries_other))
-        
-        self.diag(self.battle_info(me, other))
-        
-        while me.active and other.active:
-            if won: # we won the last round, so we can attack again.
-                won, injuries_self, injuries_other = self.select_battle_action(me, other)
-            else: 
-                self.diag(other.name + " attacks you.")
-                won, injuries_self, injuries_other = self.select_battle_style(me, other, attacker=False)
-            
-            self.diag(self.battle_round_result(me, other, won, injuries_self, injuries_other))
-            
-            self.diag(self.battle_info(me, other))
-        
-        if me.active: 
-            return True # We won
-        else: 
-            return False # We lost
-    
-    def battle_info(self, me, other): 
-        """Status information about a battle.
-        
-        @return: Completely formatted String to display. """
-        return "\n" + me.battle_stats() + "\n\n" + other.battle_stats() + "\n"
-    
-    def battle_round_result(self, me, other, won, injuries_self, injuries_other): 
-        """Return the result of one round of battle. Called with the battle results (won, injuries_self, injuries_other)."""
-        if won: 
-            scribble = _("\nYou won this round.")
-            if injuries_other[2] != 0: 
-                scribble += "\n" + other.name + _(" took ") + str(injuries_other[2]) + _(" points of damage")
-                if injuries_other[0] == 1: 
-                    scribble += _(" and a deep wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
-                elif injuries_other[1] == 1: 
-                    scribble += _(" and a critical wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
-                else: scribble += "."
-        else: 
-            scribble = _("\nYou didn't win this round.")
-            if injuries_self[2] != 0: 
-                scribble += "\n" + _("and you took ") + str(injuries_self[2]) + _(" points of damage")
-                if injuries_self[0] == 1: 
-                    scribble += _(" and a deep wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
-                elif injuries_self[1] == 1: 
-                    scribble += _(" and a critical wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
-                else: scribble += "."
-        return scribble
-    
-    def select_battle_action(self, me, other, attack=True): 
-        """Ask which action to take in the battle.
-        
-        @param me: The player char. 
-        @type me: Char
-        @param other: The enemy. 
-        @type other: Char
-        
-        @param attack: Whether the character is the attacker. 
-        @type attack: True/False
-        
-        @return: The result of the battle (won or lost, wounds)."""
-        
-        if self.ask('Do you want to attack ' + other.name + '? (Yes, no) ').lower() in ['yes', 'y', '']: 
-            self.diag("You attack " + other.name + ".")
-            won, injuries_self, injuries_other = self.select_battle_style(me, other, attacker=True)
-        else:
-            self.diag("You don't attack, so you could do something else this round, if this was already implemented.")
-            won, injuries_self, injuries_other = False, [0, 0, 0], [0, 0, 0]
-        return won, injuries_self, injuries_other 
-        
-    def select_battle_style(self, me, other, attacker): 
-        """Select how to fight.
-        @param attacker: Is me the attacker? 
-        @type: Bool
-        """
-        styles_self = []
-        style = self.ask("How do you want to fight? (Usual, defensive, target head)")
-        if style.lower() in ["target head", "head", "h"]: 
-            styles_self.append("target head")
-        elif style.lower() in ["defensive", "d"]: 
-            styles_self.append("defensive")
-        # TODO: Use the style. 
-        if attacker: 
-            won, injuries_self, injuries_other = me.fight_round(other, styles_self=styles_self)
-        else: 
-            won, injuries_other, injuries_self = other.fight_round(me, styles_other=styles_self)
-            won = not won
-        return won, injuries_self, injuries_other
-    
-    def battle_stats(self):
-        """@return: A string with battle status information, formatted as battle stats"""
-        scrib = _("---battle-stats for ") + _(self.name) + _("---")
-        scrib += _('\nLife: ') + str(self.TP) + _(" of ") + str(self.bTP)
-        scrib += _('\nWounds: ') + str(self.wounds[0]) + _(" - crippling wounds: ") + str(self.wounds[1])
-        scrib += _("\nSkill: ") + str(self.attack)
-        scrib += _("\nWeapon: ") + str(self.weapon)
-        scrib += _("\nArmor: ") + str(self.armor)
-        scrib += _("\n---/battle-stats---")
-        return scrib
-    
-    def fight_round(self,  other, styles_self=[], styles_other=[]):
-        """One battle action against another char.
-        
-    @param styles_self: The different styles the char should use (defense, pull back, escape, target: area). 
-    @type styles_self: A list of Strings. 
-    
-    @param styles_other: The different styles the enemy uses. 
-    @type styles_other: A list of Strings. 
-    
-    @return: [ If the char won (bool), [your new wounds, critical, taken tp damage], [the 
-enemies new wounds, critical, taken tp damage] ]
-
-    Plans: 
-        - TODO: Add options for own fight style. 
-        - TODO: Add options for other fight style. 
-        
-    Planned options for own fight style: 
-        - defense (+6, no damage enemy)
-        - pull back (+9, no damage enemy)
-        - try to escape. 
-        - target specific body area for additional damage. 
-        - Shield/evasion (treshold for the enemies diff, below which no hit was archieved).
-    
-    Ideas: 
-        - Define a damage multiplier, which shows how effective the damage type is against the specific enemy -> do that in the char itself. 
-        - Define the effectivity of the armor against the weapon. 
-        - Get the treshold directly from the char. 
-."""
-       # Initialize all variables empty
-        won = None #: Did we win this round?
-        mods_self = [] #: The modifiers for the protagonists attack roll. 
-        mods_other = [] #: The modifiers for the enemies attack roll. 
-        deep_wounds_self, deep_wounds_other, critical_wounds_self, critical_wounds_other = 0, 0, 0, 0
-        
-        
-        # Apply the effects of the fighting styles. 
-            # For the attacker
-        # The defensive style gives 6 points bonus, but the other char won't take any damage. 
-        if "defensive" in styles_self: 
-            mods_self.append(+6)
-        # Targetting the head gives 6 points malus, but increases the damage by 18 points. 
-        if "target head" in styles_self: 
-            mods_self.append(-6)
-            
-            # For the defender
-        # The defensive style gives 6 points bonus, but the other char won't take any damage. 
-        if "defensive" in styles_other: 
-            mods_other.append(+6)
-        # Targetting the head gives 6 points malus, but increases the damage by 18 points. 
-        if "target head" in styles_other: 
-            mods_other.append(-6)
-        
-        
-        #: The damage we get
-        self.damage_self = 0
-        #: The damage the other gets
-        self.damage_other = 0
-        
-        # Do the rolls for both fighters. 
-        attack_self = self.attack_roll(mods=mods_self)
-        attack_other = other.attack_roll(mods=mods_other)
-        
-        # If I throw higher
-        if attack_self > attack_other: 
-            won = True
-            if not "defensive" in styles_self: 
-                # Now check for damage (we hit)
-                # The damage consists of several factors. 
-                # First the difference between the attack rolls. 
-                self.damage_other += attack_self - attack_other
-                # Then the damage of our weapon. 
-                self.damage_other += self.dam
-                # And substracted the armor of the other. 
-                self.damage_other -= other.arm
-                
-                # For specific body ares, the damage increases. 
-                if "target head" in styles_self: 
-                    self.damage_other += 18
-        
-                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
-                if self.damage_other < 0: 
-                    self.damage_other = 0
-                
-                # Now actually do the damage. This returns a tuple: (new deep wounds, new critical wounds)
-                deep_wounds_other, critical_wounds_other = other.damage(tp=self.damage_other)
-        
-        # If the other rolls better
-        elif attack_self < attack_other: 
-            won = False
-            # Check for our damage (the other hit)
-            if not "defensive" in styles_other: 
-                # The damage consists of several factors. 
-                # First the difference between the attack rolls. 
-                self.damage_self += attack_other - attack_self
-                # Then the damage of our weapon. 
-                self.damage_self += other.dam
-                # And substracted the armor of the other. 
-                self.damage_self -= self.arm
-                
-                # For specific body ares, the damage increases. 
-                if "target head" in styles_other: 
-                    self.damage_self += 18
-    
-                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
-                if self.damage_self < 0: 
-                    self.damage_self = 0
-                
-                # Now actually take the damage. This returns a tuple: (new deep wounds, new critical wounds)
-                deep_wounds_self, critical_wounds_self = self.damage(tp=self.damage_self)
-
-        # If we get the same result, the attacker wins, us. 
-        else:   
-            won = True
-            if not "defensive" in styles_self: 
-                # Now check for damage (we hit)
-                # The damage consists of several factors. 
-                # First the difference between the attack rolls. 
-                self.damage_other += attack_self - attack_other
-                # Then the damage of our weapon. 
-                self.damage_other += self.dam
-                # And substracted the armor of the other. 
-                self.damage_other -= other.arm
-                
-                # For specific body ares, the damage increases. 
-                if "target head" in styles_self: 
-                    self.damage_other += 18
-            
-                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
-                if self.damage_other < 0: 
-                    self.damage_other = 0
-                
-                # Now actually do the damage. This returns a tuple: (new deep wounds, new critical wounds)
-                deep_wounds_other, critical_wounds_other = other.damage(tp=self.damage_other)
-            
-        return won, [deep_wounds_self, critical_wounds_self, self.damage_self], [deep_wounds_other, critical_wounds_other, self.damage_other]
-    
-
-class Story(UserInteraction, Dialogs): 
-    """The main component for telling stories. Subclass this to change all behaviour."""
-    def __init__(self, *args, **kwds): 
-        """The main component for telling stories."""
-        super(Story, self).__init__(*args, **kwds)
-    
-    def story(self, data=None, *args, **kwds):
-        """Tell a part of the story."""
-        if data is not None: 
-            data = _(data)
-            for i in data.split("\n"): 
-                self.diag(i, localize=False, *args, **kwds)
-    
-    def save(self, chars=[], *args, **kwds):
-            """Save the current state."""
-            for i in chars:
-                    i.save()
-    
-    def give_exp(self, char, amount=0): 
-        """Give experience to only one char."""
-        for i in self.get_experience([char], amount=amount).splitlines(): 
-            self.diag(i)
-
-
-class MissingScriptingFunction(Exception): 
-    """A warning to display if any necessary scripting function isn't implemented."""
-    def __init__(self, func, implementation = None): 
-        self.func = func
-        self.implementation = implementation
-        pass
-    def __str__(self): 
-        if self.implementation is None: 
-            return "The function " + str(self.func) + " must be implemented by every rpg scripting module to allow for easy changing of function behaviour."
-        else: 
-            return "The function " + str(self.func) + " must be implemented by every rpg scripting module to allow for easy changing of function behaviour." \
-                    + "\nThe simplest way is to just add the following lines to your script: " \
-                    + "\n\nstory_helper = Story()\n" \
-                    + self.implementation
-        
-
-### Functions ###
-
-def _(text):
-    '''String function to allow localizing later on. '''
-    return str(text)
-
-## Functions needed to be implemented in EVERY simple rpg scripting module (changing their effect for all places where they get used can only be done in the Story class) ###
-def ask(question, *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def ask(question, *args, **kwds): 
-    return story_helper.ask(question, *args, **kwds)""")
-    
-def diag(text, localize=True, autoscroll=False, *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def diag(text, localize=True, autoscroll=False, *args, **kwds): 
-    return story_helper.diag(text, localize=localize, autoscroll=autoscroll, *args, **kwds)""")
-
-def story(text=None, *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def story(text=None, *args, **kwds): 
-    return story_helper.story(text, *args, **kwds)""")
-
-def give_exp(char, amount, *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def give_exp(char, amount, *args, **kwds): 
-    return story_helper.give_exp(char, amount, *args, **kwds)""")
-
-def save(chars=[], *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def save(chars=[], *args, **kwds): 
-    return story_helper.save(chars=chars, *args, **kwds)""")
-
-def battle(me, other, *args, **kwds): 
-    raise MissingScriptingFunction(ask, implementation = """def battle(me, other, *args, **kwds): 
-    return me.battle(other, *args, **kwds)""")
-
-
-
-### Self-Test ###
-
-def _test(): 
-    """Do all doctests."""
-    from doctest import testmod
-    testmod()
-
-if __name__ == "__main__": 
-    _test()

lib/textrpg.py

-#!/usr/bin/env python
-# encoding: utf-8
-
-"""TextRPG - Simple TextRPG module built on top of the 1d6 RPG library.
-
-Usage: 
-    - ministory_helper.py 
-    Test the ministory (a testcase for the textrpg module)
-    - textrpg.py 
-    Start the internal test story of the textrpg. 
-
-Plans: 
-    - put all functions which need diag or ask or similar into a class, 
-      so diag and ask can be overridden by other modules (doesnt work right now). 
-    - Simple to use functions in easy to read scriptfiles in the style of the ministory file. 
-    - char.compete(other, skill_name) -> See who wins and by how much. 
-    - a basic implementation as minimal api reference for anyrpg plugins.
-    - Show the text letter by letter, if that's possible. 
-    - Add the basic scripting function "python_interpreter(startup_data)", which shows an interactive python interpreter with the startup data already entered and interpreted. 
-
-
-Ideas: 
-    - Lazy loading modules, to be able to print stuff at once without having to print before the imports.
-    - Add getting experience for groups and show the chars together (only one experience header instead of one per char). 
-
-
-Basic design principles for the scripting language: 
-    
-    - The action is character centered wherever possible and useful. 
-       -> char.say(text) instead of dialog(char, text)
-    
-    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
-       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
-    
-    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
-       -> save([char1, char2]) instead of char1.save() char2.save()
-    
-    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
-       -> For example AI.choose_the_way(players_answer) or music.action()
-    
-    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story_helper. 
-       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
-    
-    - Actions should be written as verb_noun or simply verb. 
-       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
-    
-    - In the story function, an action is a parameter of the story. 
-       -> story(switch_background_image="bg_image.png")
-
-
-Basic design principles for the scripting language: 
-    
-    - The action is character centered wherever possible and useful. 
-       -> char.say(text) instead of dialog(char, text)
-    
-    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
-       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
-    
-    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
-       -> save([char1, char2]) instead of char1.save() char2.save()
-    
-    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
-       -> For example AI.choose_the_way(players_answer) or music.action()
-    
-    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story. 
-       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
-    
-    - Actions should be written as verb_noun or simply verb. 
-       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
-
-The code for the TextRPG can be found at U{http://dreehg.org/ArneBab/textrpg}
-
-"""
-
-from anyrpg import __copyright__, __url__, __author__
-
-__copyright__ = """ 
-  rpg-1d6 - A general roleplaying backend. 
-  -> http://rpg-1d6.sf.net
------------------------------------------------------------------ 
-© Copyright by Arne Babenhauserheide, 2008  (arne_bab@web.de) 
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 3 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-  MA 02110-1301 USA
-
-""" 
-__version__   = '0.3' 
-__author__    = 'Arne Babenhauserheide' 
-# __date__      = '7th March 2007' 
-__url__       = 'http://rpg-1d6.sf.net' 
-
-
-print "...Loading rpg library..."
-
-# AnyRPG classes
-from anyrpg import Char
-from anyrpg import Story as any_story
-# AnyRPG function for localizing. 
-from anyrpg import _
-
-
-# Changing things. I want to display "..." in front of every blank story line. 
-
-class Story(any_story): 
-    def __init__(self, *args, **kwds): 
-        super(Story, self).__init__(*args, **kwds)
-    
-    def story(self, data=None, *args, **kwds): 
-        """Tell a part of the story.
-        
-        Overridden to show "..." instead of blank lines (override commented out). """
-        if data is not None: 
-            data = _(data)
-            for i in data.split("\n"): 
-                #if i.rstrip() == "": 
-                #    self.diag("...", localize=False)
-                #else: 
-                    self.diag(i, localize=False)
-        
-
-# Define helper functions. 
-story_helper = Story()
-
-### Lines needed in EVERY simple rpg scripting module (changing their effect for all places where they get used can only be done in the Story class) ###
-def ask(question, *args, **kwds): 
-    return story_helper.ask(question, *args, **kwds)
-
-def diag(text, localize=True, autoscroll=False, *args, **kwds): 
-    return story_helper.diag(text, localize=localize, autoscroll=autoscroll, *args, **kwds)
-
-def story(text=None, *args, **kwds): 
-    return story_helper.story(text, *args, **kwds)
-
-def give_exp(char, amount, *args, **kwds): 
-    return story_helper.give_exp(char, amount, *args, **kwds)
-
-def save(chars=[], *args, **kwds): 
-    return story_helper.save(chars=chars, *args, **kwds)
-
-def battle(me, other, *args, **kwds): 
-    return me.battle(other, *args, **kwds)
-
-
-### Test story lines ###
-
-def greet(char): 
-    diag("Old man: Welcome traveller. You've come to the right place to learn about your heritage.")
-    diag("Sadly you aren' well liked around here.")
-    diag("Heges for example didn't like your father too much.")
-    diag("Oh well, that was an understatment. You should better prepare yourself to face him. I think he'd love to see your face in the mud. Here's my knife. I like fights to be fair.")
-    diag("...")
-    diag("You say you don't know who we think you are?")
-    diag("Well, at least tell me your name then, and I'll tell you a bit about your father, after you won.")
-    char.name = raw_input("My Name: ")
-    diag("You've got a nice name, " + char.name + ". Good luck!")
-
-
-if __name__ == "__main__": 
-    print "...Creating main character..."
-    char = Char()
-    greet(char)
-    print "...Creating enemy character..."
-    choss = Char(source='tag:1w6.org,2008:Hegen')
-    choss.name = "Hegen"
-    won = battle(char, choss)
-    if won: 
-        diag(char.name + " won the fight.")
-    else: 
-        diag(choss.name + " won the fight.")
-    give_exp(char, 3)
-    choss.upgrade(3)
-    if won: 
-        diag("Well done " + char.name + ". I knew my trust in you was well placed. Now about your father...")
-    else: 
-        diag("I didn't expect you to lose to him. Well, fate is a harsh teacher. Better luck next time!")
-    

rpg_lib/anyrpg.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+"""AnyRPG - Basic functions and classes for simple RPG scripting modules.
+
+It contains the basic functions any RPG scripting module which wants to be compatible with TextRPG stories needs to provide. 
+
+TODO: Add doctests, since it begins to become more complex... 
+
+Plans: 
+    - Simple to use functions in easy to read scriptfiles in the style of the ministory file. 
+    - char.compete(other, skill_name) -> See who wins and by how much. 
+
+Ideas: 
+    - Lazy loading modules, to be able to print stuff at once without having to print before the imports.
+    - Add getting experience for groups and show the chars together (only one experience header instead of one per char). 
+
+
+Basic design principles for the scripting language: 
+    
+    - The action is character centered wherever possible and useful. 
+       -> char.say(text) instead of dialog(char, text)
+    
+    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
+       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
+    
+    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
+       -> save([char1, char2]) instead of char1.save() char2.save()
+    
+    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
+       -> For example AI.choose_the_way(players_answer) or music.action()
+    
+    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story. 
+       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
+    
+    - Actions should be written as verb_noun or simply verb. 
+       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
+     
+    - In the story function, an action is a parameter of the story. 
+       -> story(switch_background_image="bg_image.png")
+     
+
+Design:
+    - revert: story() is a function, but should be heavily overloaded, so it gets 
+used for any kind of interacion with the setting. -> story(background="...", 
+show_image="...", clear_images=True, background_musi="...", play_sound="...", ...)
+      Reason: The story is the central background. 
+      It creates the setting, just like an exposition. 
+      So it can be treated in a special way. 
+      This means: Doing it this way makes the scripts appear more natural (to me). 
+      Also this allows story() to rearrange the order of passed arguments, if all get passed in one step -> a simpler way to say "new scene". 
+
+
+This (and other) code can be found at U{http://freehg.org/ArneBab/textrpg}
+
+Doctests: 
+    >>> story_helper = Story()
+    >>> story_helper.story("The flow changes", autoscroll=True)
+    The flow changes
+    >>> story_helper.story("", autoscroll=True)
+    <BLANKLINE>
+
+"""
+
+# Structure for the metadata inspired by Fufezan: 
+# -> http://fufezan.net/python.php
+__copyright__ = """ 
+  TextRPG - Simple TextRPG module built on top of the 1d6 RPG library.
+  -> http://freehg.org/ArneBab/textrpg
+----------------------------------------------------------------- 
+© 2008 - 2008 Copyright by Arne Babenhauserheide(arne_bab@web.de) 
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+  MA 02110-1301 USA
+
+""" 
+__author__    = 'Arne Babenhauserheide' 
+# __date__      = '7th March 2007' 
+__url__       = 'http://rpg-1d6.sf.net' 
+
+__version__   = '0.1' 
+
+from textrpg_1d6 import Char as ews_char
+from time import sleep # for autoscrolling
+
+### Classes ###
+
+class UserInteraction(object): 
+    """Basic user interaction: Showing and asking things."""
+    def __init__(self, *args, **kwds): 
+        super(UserInteraction, self).__init__(*args, **kwds)
+        
+    def ask(self, question=None, *args, **kwds): 
+        """Ask a question.
+        
+        Note: Not console based implementations will want to overwrite this. """
+        if question is not None: 
+            return raw_input(_(question) + " ")
+    
+    def diag(self, data, localize=True, autoscroll=False, *args, **kwds):
+        if localize: 
+            text = _(data)
+        else: text = data 
+    
+        if not autoscroll: 
+            raw_input(text)
+        else: 
+            print text
+            # First sleep 1/10th second. This ensures that the text gets shown before sleeping.
+            sleep(0.1)
+            sleep((len(text) - 1)*0.1)
+
+class Dialogs(object): 
+    """Basic dialogs. 
+    
+    A dialog never interacts with the user directly, it just provides template for otehr code.
+    
+    If you want a specific interaction, write a function in UserInteraction, or split the dialog and interact via the higher classes (i.e. Char or Story)."""
+    def __init__(self, *args, **kwds): 
+        super(Dialogs, self).__init__(*args, **kwds)
+    
+    def get_experience(self, chars, amount=0):
+        """Show the experience the chars get and what they do with it."""
+        text = ""
+        print self.get_experience_header(chars=chars, amount=amount)
+            
+        # Info text for each char. 
+        for i in chars: 
+            result = i.incremental_upgrade(amount=1)
+            if result: 
+                text += result 
+            
+        # Dialog footer. 
+        text += self.get_experience_footer(chars, amount=amount)
+        return text
+    
+    def get_experience_header(self, chars, amount=0):
+        """@return: The header line of the experience dialog."""
+        scribble = ""
+        if len(chars) == 1: 
+            scribble += "\n***experience of " + chars[0].name + "***\n"
+            scribble += chars[0].name + " got " + str(amount) + " experience."
+        else: 
+            scribble += "\n***experience***\n"
+            scribble += "The characters got " + str(amount) + " experience."
+        return scribble
+    
+    def get_experience_footer(self, chars, amount=0):
+        """@return: The header line of the experience dialog."""
+        return "***/experience***\n"
+    
+    
+    def upgrade_info(self, char, amount): 
+        """Return the effects of improving the char by the given amount of points/Strichen."""
+        upgrade = char.upgrade(amount)
+        item_name = " ".join(upgrade[0].items()[0][0])
+        old_value = upgrade[0].items()[0][1]["Zahlenwert"] 
+        new_value = upgrade[1].items()[0][1]["Zahlenwert"]
+        if old_value < new_value:
+            return char.name + " raised " + item_name + " from " + str(old_value) + " to " + str(new_value) + "\n"
+        else: 
+            return False
+
+
+class Char(ews_char, UserInteraction, Dialogs):
+    """A Char is any character in the game, those from the player as well as others."""
+    def __init__(self, template=False, *args, **kwds): 
+        """A Char is any character in the game, those from the player as well as others."""
+        super(Char, self).__init__(template=template, *args, **kwds)
+        self.battle_diff_treshold = 4 #: The treshold of the char below which no hit is scored. 
+    
+    def say(self, data): 
+        """Say something -> Show that the char says it."""
+        data = _(data)
+        for i in data.split("\n"): 
+            self.diag(self.name + ': ' + i, localize=False)
+    
+    def act(self, data): 
+        """Do something -> Show that the char does it in the style "<name> walks away.".
+        
+        Usage: 
+            >>> char = Char(source="tag:1w6.org,2008:Mins")
+            >>> char.act("walks away.")
+            Mins walks away.
+        """
+        data = _(data)
+        for i in data.split("\n"): 
+            self.diag(self.name + ' ' + i, localize=False)
+        
+    def compete_skill(self, other, skill_name, self_mods=[], other_mods=[]): 
+        """Compete with the other char in the specified skill. 
+        
+        @return If we won and by how much: (won, diff). Diff is always >=0. 
+        """
+        my_result = self.roll(self.get_effective_skill_value(skill_name, related_skills=[], related_attributes=[]), mods=self_mods)
+        other_result = other.roll(other.get_effective_skill_value(skill_name, related_skills=[], related_attributes=[]), mods=other_mods)
+        return my_result > other_result, abs(my_result - other_result)
+    
+    def get_exp(self, amount=0): 
+        """Get experience and show it."""
+        for i in self.get_experience([self], amount).splitlines(): 
+            self.diag(i)
+    
+    def incremental_upgrade(self, amount=0): 
+        # Upgrade in single point steps, so the experience gets spread a bit. 
+        # if it's less than two points, use it completely. 
+        if amount <= 2: 
+            text = self.upgrade_info(self, amount)
+        # If it's more than one point, spread all but one in single points 
+        # and at last improve by 1 plus the remaining fraction. 
+        # With this, no value gets less than one point/Strich 
+        # (no use in spreading points which can only give an increase by pure chance). 
+        else: 
+            text = ""
+            for j in range(int(amount) -1): 
+                text += self.upgrade_info(self, 1)
+            text += self.upgrade_info(self, amount - int(amount) + 1)
+        return text
+    
+    def battle(self, other): 
+        """Fight a deadly battle."""
+        return self.fight_while_standing(self, other)
+    
+    def fight_while_standing(self, me, other):
+        '''Fight as long as both characters are still active.
+        
+        Plans: 
+            - TODO: Select fight styles, when you attack as well as when the other attacks. 
+        '''
+        
+        # Show the battle status of both chars. 
+        self.diag(self.battle_info(me, other))
+        
+        # Ask the player which action to take.        
+        self.diag(other.name + ' comes closer.')
+        won, injuries_self, injuries_other = self.select_battle_action(me, other)
+        
+        self.diag(self.battle_round_result(me, other, won, injuries_self, injuries_other))
+        
+        self.diag(self.battle_info(me, other))
+        
+        while me.active and other.active:
+            if won: # we won the last round, so we can attack again.
+                won, injuries_self, injuries_other = self.select_battle_action(me, other)
+            else: 
+                self.diag(other.name + " attacks you.")
+                won, injuries_self, injuries_other = self.select_battle_style(me, other, attacker=False)
+            
+            self.diag(self.battle_round_result(me, other, won, injuries_self, injuries_other))
+            
+            self.diag(self.battle_info(me, other))
+        
+        if me.active: 
+            return True # We won
+        else: 
+            return False # We lost
+    
+    def battle_info(self, me, other): 
+        """Status information about a battle.
+        
+        @return: Completely formatted String to display. """
+        return "\n" + me.battle_stats() + "\n\n" + other.battle_stats() + "\n"
+    
+    def battle_round_result(self, me, other, won, injuries_self, injuries_other): 
+        """Return the result of one round of battle. Called with the battle results (won, injuries_self, injuries_other)."""
+        if won: 
+            scribble = _("\nYou won this round.")
+            if injuries_other[2] != 0: 
+                scribble += "\n" + other.name + _(" took ") + str(injuries_other[2]) + _(" points of damage")
+                if injuries_other[0] == 1: 
+                    scribble += _(" and a deep wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
+                elif injuries_other[1] == 1: 
+                    scribble += _(" and a critical wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
+                else: scribble += "."
+        else: 
+            scribble = _("\nYou didn't win this round.")
+            if injuries_self[2] != 0: 
+                scribble += "\n" + _("and you took ") + str(injuries_self[2]) + _(" points of damage")
+                if injuries_self[0] == 1: 
+                    scribble += _(" and a deep wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
+                elif injuries_self[1] == 1: 
+                    scribble += _(" and a critical wound.") # You never get more than one wound per enemy in one round in the 1d6 rpg. 
+                else: scribble += "."
+        return scribble
+    
+    def select_battle_action(self, me, other, attack=True): 
+        """Ask which action to take in the battle.
+        
+        @param me: The player char. 
+        @type me: Char
+        @param other: The enemy. 
+        @type other: Char
+        
+        @param attack: Whether the character is the attacker. 
+        @type attack: True/False
+        
+        @return: The result of the battle (won or lost, wounds)."""
+        
+        if self.ask('Do you want to attack ' + other.name + '? (Yes, no) ').lower() in ['yes', 'y', '']: 
+            self.diag("You attack " + other.name + ".")
+            won, injuries_self, injuries_other = self.select_battle_style(me, other, attacker=True)
+        else:
+            self.diag("You don't attack, so you could do something else this round, if this was already implemented.")
+            won, injuries_self, injuries_other = False, [0, 0, 0], [0, 0, 0]
+        return won, injuries_self, injuries_other 
+        
+    def select_battle_style(self, me, other, attacker): 
+        """Select how to fight.
+        @param attacker: Is me the attacker? 
+        @type: Bool
+        """
+        styles_self = []
+        style = self.ask("How do you want to fight? (Usual, defensive, target head)")
+        if style.lower() in ["target head", "head", "h"]: 
+            styles_self.append("target head")
+        elif style.lower() in ["defensive", "d"]: 
+            styles_self.append("defensive")
+        # TODO: Use the style. 
+        if attacker: 
+            won, injuries_self, injuries_other = me.fight_round(other, styles_self=styles_self)
+        else: 
+            won, injuries_other, injuries_self = other.fight_round(me, styles_other=styles_self)
+            won = not won
+        return won, injuries_self, injuries_other
+    
+    def battle_stats(self):
+        """@return: A string with battle status information, formatted as battle stats"""
+        scrib = _("---battle-stats for ") + _(self.name) + _("---")
+        scrib += _('\nLife: ') + str(self.TP) + _(" of ") + str(self.bTP)
+        scrib += _('\nWounds: ') + str(self.wounds[0]) + _(" - crippling wounds: ") + str(self.wounds[1])
+        scrib += _("\nSkill: ") + str(self.attack)
+        scrib += _("\nWeapon: ") + str(self.weapon)
+        scrib += _("\nArmor: ") + str(self.armor)
+        scrib += _("\n---/battle-stats---")
+        return scrib
+    
+    def fight_round(self,  other, styles_self=[], styles_other=[]):
+        """One battle action against another char.
+        
+    @param styles_self: The different styles the char should use (defense, pull back, escape, target: area). 
+    @type styles_self: A list of Strings. 
+    
+    @param styles_other: The different styles the enemy uses. 
+    @type styles_other: A list of Strings. 
+    
+    @return: [ If the char won (bool), [your new wounds, critical, taken tp damage], [the 
+enemies new wounds, critical, taken tp damage] ]
+
+    Plans: 
+        - TODO: Add options for own fight style. 
+        - TODO: Add options for other fight style. 
+        
+    Planned options for own fight style: 
+        - defense (+6, no damage enemy)
+        - pull back (+9, no damage enemy)
+        - try to escape. 
+        - target specific body area for additional damage. 
+        - Shield/evasion (treshold for the enemies diff, below which no hit was archieved).
+    
+    Ideas: 
+        - Define a damage multiplier, which shows how effective the damage type is against the specific enemy -> do that in the char itself. 
+        - Define the effectivity of the armor against the weapon. 
+        - Get the treshold directly from the char. 
+."""
+       # Initialize all variables empty
+        won = None #: Did we win this round?
+        mods_self = [] #: The modifiers for the protagonists attack roll. 
+        mods_other = [] #: The modifiers for the enemies attack roll. 
+        deep_wounds_self, deep_wounds_other, critical_wounds_self, critical_wounds_other = 0, 0, 0, 0
+        
+        
+        # Apply the effects of the fighting styles. 
+            # For the attacker
+        # The defensive style gives 6 points bonus, but the other char won't take any damage. 
+        if "defensive" in styles_self: 
+            mods_self.append(+6)
+        # Targetting the head gives 6 points malus, but increases the damage by 18 points. 
+        if "target head" in styles_self: 
+            mods_self.append(-6)
+            
+            # For the defender
+        # The defensive style gives 6 points bonus, but the other char won't take any damage. 
+        if "defensive" in styles_other: 
+            mods_other.append(+6)
+        # Targetting the head gives 6 points malus, but increases the damage by 18 points. 
+        if "target head" in styles_other: 
+            mods_other.append(-6)
+        
+        
+        #: The damage we get
+        self.damage_self = 0
+        #: The damage the other gets
+        self.damage_other = 0
+        
+        # Do the rolls for both fighters. 
+        attack_self = self.attack_roll(mods=mods_self)
+        attack_other = other.attack_roll(mods=mods_other)
+        
+        # If I throw higher
+        if attack_self > attack_other: 
+            won = True
+            if not "defensive" in styles_self: 
+                # Now check for damage (we hit)
+                # The damage consists of several factors. 
+                # First the difference between the attack rolls. 
+                self.damage_other += attack_self - attack_other
+                # Then the damage of our weapon. 
+                self.damage_other += self.dam
+                # And substracted the armor of the other. 
+                self.damage_other -= other.arm
+                
+                # For specific body ares, the damage increases. 
+                if "target head" in styles_self: 
+                    self.damage_other += 18
+        
+                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
+                if self.damage_other < 0: 
+                    self.damage_other = 0
+                
+                # Now actually do the damage. This returns a tuple: (new deep wounds, new critical wounds)
+                deep_wounds_other, critical_wounds_other = other.damage(tp=self.damage_other)
+        
+        # If the other rolls better
+        elif attack_self < attack_other: 
+            won = False
+            # Check for our damage (the other hit)
+            if not "defensive" in styles_other: 
+                # The damage consists of several factors. 
+                # First the difference between the attack rolls. 
+                self.damage_self += attack_other - attack_self
+                # Then the damage of our weapon. 
+                self.damage_self += other.dam
+                # And substracted the armor of the other. 
+                self.damage_self -= self.arm
+                
+                # For specific body ares, the damage increases. 
+                if "target head" in styles_other: 
+                    self.damage_self += 18
+    
+                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
+                if self.damage_self < 0: 
+                    self.damage_self = 0
+                
+                # Now actually take the damage. This returns a tuple: (new deep wounds, new critical wounds)
+                deep_wounds_self, critical_wounds_self = self.damage(tp=self.damage_self)
+
+        # If we get the same result, the attacker wins, us. 
+        else:   
+            won = True
+            if not "defensive" in styles_self: 
+                # Now check for damage (we hit)
+                # The damage consists of several factors. 
+                # First the difference between the attack rolls. 
+                self.damage_other += attack_self - attack_other
+                # Then the damage of our weapon. 
+                self.damage_other += self.dam
+                # And substracted the armor of the other. 
+                self.damage_other -= other.arm
+                
+                # For specific body ares, the damage increases. 
+                if "target head" in styles_self: 
+                    self.damage_other += 18
+            
+                # Clean out negative damage. If the damage is below zero, the armor caught all damage. 
+                if self.damage_other < 0: 
+                    self.damage_other = 0
+                
+                # Now actually do the damage. This returns a tuple: (new deep wounds, new critical wounds)
+                deep_wounds_other, critical_wounds_other = other.damage(tp=self.damage_other)
+            
+        return won, [deep_wounds_self, critical_wounds_self, self.damage_self], [deep_wounds_other, critical_wounds_other, self.damage_other]
+    
+
+class Story(UserInteraction, Dialogs): 
+    """The main component for telling stories. Subclass this to change all behaviour."""
+    def __init__(self, *args, **kwds): 
+        """The main component for telling stories."""
+        super(Story, self).__init__(*args, **kwds)
+    
+    def story(self, data=None, *args, **kwds):
+        """Tell a part of the story."""
+        if data is not None: 
+            data = _(data)
+            for i in data.split("\n"): 
+                self.diag(i, localize=False, *args, **kwds)
+    
+    def save(self, chars=[], *args, **kwds):
+            """Save the current state."""
+            for i in chars:
+                    i.save()
+    
+    def give_exp(self, char, amount=0): 
+        """Give experience to only one char."""
+        for i in self.get_experience([char], amount=amount).splitlines(): 
+            self.diag(i)
+
+
+class MissingScriptingFunction(Exception): 
+    """A warning to display if any necessary scripting function isn't implemented."""
+    def __init__(self, func, implementation = None): 
+        self.func = func
+        self.implementation = implementation
+        pass
+    def __str__(self): 
+        if self.implementation is None: 
+            return "The function " + str(self.func) + " must be implemented by every rpg scripting module to allow for easy changing of function behaviour."
+        else: 
+            return "The function " + str(self.func) + " must be implemented by every rpg scripting module to allow for easy changing of function behaviour." \
+                    + "\nThe simplest way is to just add the following lines to your script: " \
+                    + "\n\nstory_helper = Story()\n" \
+                    + self.implementation
+        
+
+### Functions ###
+
+def _(text):
+    '''String function to allow localizing later on. '''
+    return str(text)
+
+## Functions needed to be implemented in EVERY simple rpg scripting module (changing their effect for all places where they get used can only be done in the Story class) ###
+def ask(question, *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def ask(question, *args, **kwds): 
+    return story_helper.ask(question, *args, **kwds)""")
+    
+def diag(text, localize=True, autoscroll=False, *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def diag(text, localize=True, autoscroll=False, *args, **kwds): 
+    return story_helper.diag(text, localize=localize, autoscroll=autoscroll, *args, **kwds)""")
+
+def story(text=None, *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def story(text=None, *args, **kwds): 
+    return story_helper.story(text, *args, **kwds)""")
+
+def give_exp(char, amount, *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def give_exp(char, amount, *args, **kwds): 
+    return story_helper.give_exp(char, amount, *args, **kwds)""")
+
+def save(chars=[], *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def save(chars=[], *args, **kwds): 
+    return story_helper.save(chars=chars, *args, **kwds)""")
+
+def battle(me, other, *args, **kwds): 
+    raise MissingScriptingFunction(ask, implementation = """def battle(me, other, *args, **kwds): 
+    return me.battle(other, *args, **kwds)""")
+
+
+
+### Self-Test ###
+
+def _test(): 
+    """Do all doctests."""
+    from doctest import testmod
+    testmod()
+
+if __name__ == "__main__": 
+    _test()

rpg_lib/textrpg.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+"""TextRPG - Simple TextRPG module built on top of the 1d6 RPG library.
+
+Usage: 
+    - ministory_helper.py 
+    Test the ministory (a testcase for the textrpg module)
+    - textrpg.py 
+    Start the internal test story of the textrpg. 
+
+Plans: 
+    - put all functions which need diag or ask or similar into a class, 
+      so diag and ask can be overridden by other modules (doesnt work right now). 
+    - Simple to use functions in easy to read scriptfiles in the style of the ministory file. 
+    - char.compete(other, skill_name) -> See who wins and by how much. 
+    - a basic implementation as minimal api reference for anyrpg plugins.
+    - Show the text letter by letter, if that's possible. 
+    - Add the basic scripting function "python_interpreter(startup_data)", which shows an interactive python interpreter with the startup data already entered and interpreted. 
+
+
+Ideas: 
+    - Lazy loading modules, to be able to print stuff at once without having to print before the imports.
+    - Add getting experience for groups and show the chars together (only one experience header instead of one per char). 
+
+
+Basic design principles for the scripting language: 
+    
+    - The action is character centered wherever possible and useful. 
+       -> char.say(text) instead of dialog(char, text)
+    
+    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
+       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
+    
+    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
+       -> save([char1, char2]) instead of char1.save() char2.save()
+    
+    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
+       -> For example AI.choose_the_way(players_answer) or music.action()
+    
+    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story_helper. 
+       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
+    
+    - Actions should be written as verb_noun or simply verb. 
+       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
+    
+    - In the story function, an action is a parameter of the story. 
+       -> story(switch_background_image="bg_image.png")
+
+
+Basic design principles for the scripting language: 
+    
+    - The action is character centered wherever possible and useful. 
+       -> char.say(text) instead of dialog(char, text)
+    
+    - Anything which affects only one character or any interaction between only a few characters which is initiated by one of them gets called from the character via char.action(). 
+       -> char.compete_skill(char2, skill_name) instead of competition_skill(char1, char2, skill_name)
+    
+    - Anything which affects the whole scene, or a whole group of not necessarily interacting characters gets called as basic function via action() or as class in its own right via class.action(). 
+       -> save([char1, char2]) instead of char1.save() char2.save()
+    
+    - The seperate class way should only be chosen, if the class can feel like a character in its own right and needs seperate states which may or may not be persistent over subsequent runs. 
+       -> For example AI.choose_the_way(players_answer) or music.action()
+    
+    - Data should be stored inside the chars wherever possible. If a script gets started with the same character again, the situation should resemble the previous one as much as possible, except where dictated otherwise by the story. 
+       -> char.save() instead of 'on quit' store_char_data(char) + 'on start' load_char_data(char)
+    
+    - Actions should be written as verb_noun or simply verb. 
+       -> char.say() and char.compete_skill() instead of char.text() and char.skill_compete()
+
+The code for the TextRPG can be found at U{http://dreehg.org/ArneBab/textrpg}
+
+"""
+
+from anyrpg import __copyright__, __url__, __author__
+
+__copyright__ = """ 
+  rpg-1d6 - A general roleplaying backend. 
+  -> http://rpg-1d6.sf.net
+----------------------------------------------------------------- 
+© Copyright by Arne Babenhauserheide, 2008  (arne_bab@web.de) 
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+  MA 02110-1301 USA
+
+""" 
+__version__   = '0.3' 
+__author__    = 'Arne Babenhauserheide' 
+# __date__      = '7th March 2007' 
+__url__       = 'http://rpg-1d6.sf.net' 
+
+
+print "...Loading rpg library..."
+
+# AnyRPG classes
+from anyrpg import Char
+from anyrpg import Story as any_story
+# AnyRPG function for localizing. 
+from anyrpg import _
+
+
+# Changing things. I want to display "..." in front of every blank story line. 
+
+class Story(any_story): 
+    def __init__(self, *args, **kwds): 
+        super(Story, self).__init__(*args, **kwds)
+    
+    def story(self, data=None, *args, **kwds): 
+        """Tell a part of the story.
+        
+        Overridden to show "..." instead of blank lines (override commented out). """
+        if data is not None: 
+            data = _(data)
+            for i in data.split("\n"): 
+                #if i.rstrip() == "": 
+                #    self.diag("...", localize=False)
+                #else: 
+                    self.diag(i, localize=False)
+        
+
+# Define helper functions. 
+story_helper = Story()
+
+### Lines needed in EVERY simple rpg scripting module (changing their effect for all places where they get used can only be done in the Story class) ###
+def ask(question, *args, **kwds): 
+    return story_helper.ask(question, *args, **kwds)
+
+def diag(text, localize=True, autoscroll=False, *args, **kwds): 
+    return story_helper.diag(text, localize=localize, autoscroll=autoscroll, *args, **kwds)
+
+def story(text=None, *args, **kwds): 
+    return story_helper.story(text, *args, **kwds)
+
+def give_exp(char, amount, *args, **kwds): 
+    return story_helper.give_exp(char, amount, *args, **kwds)
+
+def save(chars=[], *args, **kwds): 
+    return story_helper.save(chars=chars, *args, **kwds)
+
+def battle(me, other, *args, **kwds): 
+    return me.battle(other, *args, **kwds)
+
+
+### Test story lines ###
+
+def greet(char): 
+    diag("Old man: Welcome traveller. You've come to the right place to learn about your heritage.")
+    diag("Sadly you aren' well liked around here.")
+    diag("Heges for example didn't like your father too much.")
+    diag("Oh well, that was an understatment. You should better prepare yourself to face him. I think he'd love to see your face in the mud. Here's my knife. I like fights to be fair.")
+    diag("...")
+    diag("You say you don't know who we think you are?")
+    diag("Well, at least tell me your name then, and I'll tell you a bit about your father, after you won.")
+    char.name = raw_input("My Name: ")
+    diag("You've got a nice name, " + char.name + ". Good luck!")
+
+
+if __name__ == "__main__": 
+    print "...Creating main character..."
+    char = Char()
+    greet(char)
+    print "...Creating enemy character..."
+    choss = Char(source='tag:1w6.org,2008:Hegen')
+    choss.name = "Hegen"
+    won = battle(char, choss)
+    if won: 
+        diag(char.name + " won the fight.")
+    else: 
+        diag(choss.name + " won the fight.")
+    give_exp(char, 3)
+    choss.upgrade(3)
+    if won: 
+        diag("Well done " + char.name + ". I knew my trust in you was well placed. Now about your father...")
+    else: 
+        diag("I didn't expect you to lose to him. Well, fate is a harsh teacher. Better luck next time!")
+    

rpg_lib/textrpg_1d6/__init__.py

-#!/usr/bin/env python
-# encoding: utf-8
-
-# EWS - An RPG backend module providing character management and interaction. 
-# 
-# Copyright © 2008 Arne Babenhauserheide
-# 
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>
-
-"""The ews ("Ein Wuerfel Sytem" is german for "One Die System") is a free rpg backend which covers char interaction and char management -> http://1w6.org. 
-
-Chars have attributes, abilities, edges/flaws, equipment and battle values (directly derived from the attributes and abilities). 
-
-
-Usage from command line: 
-
-    - None yet. 
-
-
-Examples: 
-
-    - None yet. 
-
-
-Use-Cases: 
-
- - Creating Chars
-    
-    Create and print a char from a tag-string
-        >>> from char import Char
-        >>> tag_string = "tag:1w6.org,2008:Human"
-        >>> char_from_tag = Char(source=tag_string, template=False) 
-    
-    template=False says: Go with the name inside the stored file or (if None is avaible) in the tagstring. 
-    
-    Else it would create a new name for it. 
-    
-    TODO: Change the default to template=False (some checking of other libs necessary for that)
-        >>> print char_from_tag
-        Name: Human
-        Sprache: Esperanto
-    
-    TODO: Create a char from a char dict. 
-    
-    TODO: Print location of character file. 
-    
-    
- - Combat
-    
-    Create two chars and let them fight one round. 
-        >>> char1 = Char()
-        >>> char2 = Char()
-        >>> print char1.wounds, char2.wounds
-        [0, 0] [0, 0]
-        >>> char1.fight_round(char2)
-        >>> result = (char1.get_battle_result_values(), char2.get_battle_result_values())  
-        >>> # Gives TP and wounds for Char 1 and 2
-    
-    Let the two chars fight a battle with the one roll battle system. 
-        >>> char1.fight_one_roll_battle(char2)
-        >>> result = (char1.get_battle_result_values(), char2.get_battle_result_values()) 
-        >>> # Dict for char1 and for char 2
-    
-    TODO: Fight a whole battle with the complex battle system. 
-    
-    
- - Attributes
-    
-    List all attributes. If the char has None, print a single space. 
-        >>> char1.attributes
-        ' '
-    
-    
- - Skills and checks
-    
-    List all skills. If the char has None, print a single space. 
-        >>> char1.skills
-        {'Nahkampf': {'Grundwert': 12, 'Striche': 3, 'Zahlenwert': 12}}
-    
-    Do a skill test (default target number is 9)
-        >>> print "Do we manage to cook a nice meal?"
-        Do we manage to cook a nice meal?
-        >>> result = char1.check_skill("cook")
-    
-    Do a skill test against another target number. 
-        >>> print "Do we manage to cook an exceptional meal?"
-        Do we manage to cook an exceptional meal?
-        >>> result = char1.check_skill("cook", MW=18)
-    
-    TODO: Check how good we manage something. 
-    
-    TODO: Check if we manage to make a roll and how good we manage it. 
-    
-    
- - Competition (skill vs. skill and similar)
-    
-    TODO: Let two chars compete for one round. 
-    
-    TODO: Let two chars do a full competition. 
-    
-    
- - Equipment
-    
-    Get the current equipment of the char. 
-        >>> for i in char1.equipment: print char1.equipment[i] 
-        {'Stoffkleidung': {'Name': 'Stoffkleidung', 'Schutz': 1}}
-        {'Waffenlos': {'Name': 'Waffenlos', 'Schaden': 1}}
-        >>> # TODO: Fix to make it nicer to use. 
-    
-    
-    Get the current combat equipment of the char (armor and weapon). 
-        >>> char1.weapon
-        {'Name': 'Waffenlos', 'Schaden': 1}
-        >>> char1.armor
-        {'Name': 'Stoffkleidung', 'Schutz': 1}
-    
-    TODO: Change armor and weapon (and weapon skill). 
-    
-    TODO: Get the current clothes of the char. 
-    
-    TODO: Change the current clothes of the char. 
-    
-    
- - Improving Chars
-    
-    Improve a char by a 3 points at random (about the value to get for one gaming session in a hreo setting). 
-        >>> char1.upgrade(3)
-    
-    Upgrade with a weighted list of attributes and skills which could be improved additionally to known skills and attributes. 
-        >>> char1.upgrade(3, object=("weighted", [("attribute",  "sensitivity", 1), ("skill", "cooking", 2)]))
-    
-    Upgrade a specific skill or attribute. 
-        >>> char1.upgrade(3, object=("skill", "talking senslessly"))
-        
-    # TODO: Add attibute explicitely. 
-    
-    
- - Saving Chars
-    
-    Save the changed (wounded but improved) Char as new template. 
-    
-    Commented out, because this creates new files. 
-        >>> # char1.name = char1.amov.tagname
-        >>> # char1.save()
-    
-    Save the changed Char as a new char and get the new tag to call it again. 
-    
-    Commented out, because this creates new files. 
-        >>> # tagstring = char1.amov.tagstring_without_name + char1.name # The tag to call the char
-        >>> # char1.save()
-        >>> # char1_again = Char(source=tagstring, template=False)
-    
-    
- - Finishing Chars off :) 
-    
-    And in the end: Die 
-        >>> char1.die()
-
-
-Plans: 
-    - Change char file format: an empty dict shoulnd't be represented by " " anymore, but by {} (the real yaml represenation of an empty dictionary). 
-
-
-Source URL (Mercurial): U{http://rpg-1d6.sf.net/hg/1d6}
-
-PyPI URL: U{http://pypi.python.org/pypi/ews}
-"""
-
-#### Package information ###
-
-__version__ = "0.1"
-
-#### Package information ###
-
-#### Imports ####
-
-from char import Char
-
-#### Imports ####
-
-#### Self-Test ####
-
-def _test():
-    """Launch the doctests."""
-    from doctest import testmod
-    testmod()
-
-if __name__ == "__main__": 
-    _test()

rpg_lib/textrpg_1d6/amov/Armee.py

-#!/usr/bin/env python
-# encoding: utf-8
-
-# Armeenverwaltung - Verwalte Armeen im lesbaren YAML Format
-# Copyright © 2007 - 2007 Arne Babenhauserheide
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301 USA
-
-"""Verwalte Dateien von Armeen
-
-Beispiel: 
->>> Schlacht = Schlacht()
->>> Schlacht.schlacht
-[(('Menschen Armee', 0.5, 0.40000000000000002), [], [('tag:1w6.org,2007:Mensch', 10, -1, 'Soldat', True), ('tag:draketo.de,2007:Sskreszta', 1, -1, 'Held', False)]), (('Goblin Armee', 0.40000000000000002, 0.40000000000000002), [], [('tag:1w6.org,2007:Goblin', 15, -1, 'Soldat', True)])]
-
- """
-
-
-### Imports ###
-
-# Für das Dateiformat brauchen wir yaml
-from rpg_lib.yaml import load as yaml_load
-
-# Um die Dateien zu laden, nutzen wir die Objekt-Klasse. 
-import Skripte.Kernskripte.Objekt as Objekt
-
-# Um immer die neuste Version zu haben brauchen wir die Versionsverwaltung
-from Versionsverwaltung import Versionen
-
-### Imports ###
-
-### Klassen ###
-
-class Armee: 
-    def __init__(self, ID=None, art=None,  tag=u"tag:1w6.org,2008:Menschen",  data=None): 
-        #: Der Identifikator der Armee-Datei
-        if ID is not None: 
-            self.ID = ID
-        elif tag is not None: 
-            # Wenn keine ID bekannt ist, lade die neuste Datei
-            versionen = Versionen(tag=tag,  kategorie=u"Armeen")
-            self.ID = versionen.neuste
-        # Wenn daten angegeben werden, sollen sie in einer neuen Version gespeichert werden. 
-        if data is not None: 
-            self.data = data #: Neue Daten, die gespeichert werden sollen. 
-            # TODO: If data is given, create a new minor version of the file. 
-        
-        #: Die Art des Charakters. Wird noch nicht verwendet. 
-        self.art = art
-        #: Das Charakterobjekt. Es bietet das dict und ein paar Methoden. 
-        self.objekt = Objekt.Objekt(ID=self.ID, template=yaml_load(self.standard_schlacht_yaml()))
-        #: Das Charakterwörterbuch mit allen Charakterdaten aus der Datei. 
-        self.armee = self.objekt.objekt
-    
-    def standard_schlacht_yaml(self): 
-    	return """# Battlefield definition: (armies)
-    # Army definition: (army_data, [groups], [chartypes])
-    # army_data definition: ('name', resignratio, fleeratio)
-    # Chartype definition: ("tag", number_of_soldiers, 'group' (-1=army), 'Type_of_chars', from_template?)
-!!python/tuple
-  - !!python/tuple
-    - Menschen Armee
-    - 0.5
-    - 0.40000000000000002
-  - []
-  - - !!python/tuple
-      - tag:1w6.org,2007:Mensch
-      - 10
-      - -1
-      - Soldat
-      - true
-
-"""
-    
-    
-
-### Klassen ###
-
-### Self-Test ###
-
-def _test(): 
-	import doctest
-	doctest.testmod()
-
-if __name__ == "__main__": 
-   _test() 
-
-if __name__ == '__main__': 
-        pass
-
-### Self-Test ###
-        

rpg_lib/textrpg_1d6/amov/Armee.py~

-#!/usr/bin/env python
-# encoding: utf-8
-
-# Armeenverwaltung - Verwalte Armeen im lesbaren YAML Format
-# Copyright © 2007 - 2007 Arne Babenhauserheide
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301 USA
-
-"""Verwalte Dateien von Armeen
-
-Beispiel: 
->>> Schlacht = Schlacht()
->>> Schlacht.schlacht
-[(('Menschen Armee', 0.5, 0.40000000000000002), [], [('tag:1w6.org,2007:Mensch', 10, -1, 'Soldat', True), ('tag:draketo.de,2007:Sskreszta', 1, -1, 'Held', False)]), (('Goblin Armee', 0.40000000000000002, 0.40000000000000002), [], [('tag:1w6.org,2007:Goblin', 15, -1, 'Soldat', True)])]
-
- """
-
-
-### Imports ###
-
-# Für das Dateiformat brauchen wir yaml
-from yaml import load as yaml_load
-
-# Um die Dateien zu laden, nutzen wir die Objekt-Klasse. 
-import Skripte.Kernskripte.Objekt as Objekt
-
-# Um immer die neuste Version zu haben brauchen wir die Versionsverwaltung
-from Versionsverwaltung import Versionen
-
-### Imports ###
-
-### Klassen ###
-
-class Armee: 
-    def __init__(self, ID=None, art=None,  tag=u"tag:1w6.org,2008:Menschen",  data=None): 
-        #: Der Identifikator der Armee-Datei
-        if ID is not None: 
-            self.ID = ID
-        elif tag is not None: 
-            # Wenn keine ID bekannt ist, lade die neuste Datei
-            versionen = Versionen(tag=tag,  kategorie=u"Armeen")
-            self.ID = versionen.neuste
-        # Wenn daten angegeben werden, sollen sie in einer neuen Version gespeichert werden. 
-        if data is not None: 
-            self.data = data #: Neue Daten, die gespeichert werden sollen. 
-            # TODO: If data is given, create a new minor version of the file. 
-        
-        #: Die Art des Charakters. Wird noch nicht verwendet. 
-        self.art = art
-        #: Das Charakterobjekt. Es bietet das dict und ein paar Methoden. 
-        self.objekt = Objekt.Objekt(ID=self.ID, template=yaml_load(self.standard_schlacht_yaml()))
-        #: Das Charakterwörterbuch mit allen Charakterdaten aus der Datei. 
-        self.armee = self.objekt.objekt
-    
-    def standard_schlacht_yaml(self): 
-    	return """# Battlefield definition: (armies)
-    # Army definition: (army_data, [groups], [chartypes])
-    # army_data definition: ('name', resignratio, fleeratio)
-    # Chartype definition: ("tag", number_of_soldiers, 'group' (-1=army), 'Type_of_chars', from_template?)
-!!python/tuple
-  - !!python/tuple
-    - Menschen Armee
-    - 0.5
-    - 0.40000000000000002
-  - []
-  - - !!python/tuple
-      - tag:1w6.org,2007:Mensch
-      - 10
-      - -1
-      - Soldat
-      - true
-
-"""
-    
-    
-
-### Klassen ###
-
-### Self-Test ###
-
-def _test(): 
-	import doctest
-	doctest.testmod()
-
-if __name__ == "__main__": 
-   _test() 
-
-if __name__ == '__main__': 
-        pass
-
-### Self-Test ###
-        

rpg_lib/textrpg_1d6/amov/Charakter.py

-#!/bin/env python
-# encoding: utf-8
-
-# Charakterverwaltung - Verwalte Charaktere im lesbaren YAML Format
-# Copyright © 2007 - 2007 Arne Babenhauserheide
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301 USA
-
-"""Manage Charakter-Objects. 
-
-Diese Datei ist ein Container für die klasse Charaktere. 
-
-Aufrufen mit ID-Objekt oder tag-string. 
-
-Beispiel: 
->>> Sskreszta = Charakter(tag=u"tag:draketo.de,2007:Sskreszta")
->>> Sskreszta.name
-'Sskreszta'
-
-ToDo: Größere Teile des Charaktersnicht mehr als attribut des OBjekts doppelspeichern, sondern nur durch Funktionen aufrufen. Das dict sollte nur einmal echt geladen werden. Die Eigenschaften des Charakters sollten mit Funktionen aus diesem Hauptdict herausgezogen werden. 
-Ausgenommen davon sind Werrte, sie sehr oft gebraucht und geänbdert werden (Geschwindkeit statt Ram-Verbrauch). 
-Aktuell wird er Charakter in etwa doppelt geladen.
- 
- #TODO: Sourcefile dir hinzufügen. """
-
-### Imports ###
-
-# Um die Dateien zu laden, nutzen wir die Objekt-Klasse. 
-import Skripte.Kernskripte.Objekt as Objekt
-
-# Und wir brauchen die Basisklasse: Object
-from Object import Object, _
-
-# Um immer die neuste Version zu haben brauchen wir die Versionsverwaltung
-from Versionsverwaltung import Versionen
-
-### Imports ###
-
-### Klassen ###
-
-class Charakter(Object): 
-    def __init__(self, ID=None, art=None,  tag=u"tag:draketo.de,2007:Sskreszta", kategorie="Charaktere", *args, **kwds): 
-        super(Charakter, self).__init__(ID=ID, art=art,  tag=tag, kategorie=kategorie, *args, **kwds)
-        self.beschreibung = self.ladeBeschreibung()
-        self.werte = self.ladeWerte()
-        self.eigenschaften = self.ladeEigenschaften()
-        self.fertigkeiten = self.ladeFertigkeiten()
-        self.kampfwerte = self.ladeKampfwerte()
-        self.ausruestung = self.ladeAusruestung()
-        self.schutz = self.ladeSchutz()
-        self.herkunft = self.ladeHerkunft()
-        self.sprache = self.ladeSprache()
-        self.region = self.ladeRegion()
-        self.stimmung = self.ladeStimmung()
-        self.kategorie = self.objekt.kategorie
-        # del self.daten # Wir müssen dieses Wörterbuch nicht löschen, 
-        # da Python es zu cachen scheint, so dass wir dadurch kein Ram sparen. 
-        # Vielleicht existiert es auch nur als symbolischer Link. 
-            
-    def ladeName(self): 
-        """Lade den Namen des Charakters. 
-        
-        Wenn der Charakter keinen Namen hat, dann erzeuge einen zufälligen."""
-        if self.daten[0][_(u"Name")] == " ": 
-            self.daten[0][_(u"Name")] = self.objekt.objekt_name()
-            self.objekt.write()
-        return self.daten[0][_(u"Name")]
-        
-    def ladeGrunddaten(self): 
-        """Lade die Grundlegenden Daten des Charakters, wie seine Beschreibung oder Herkunft. 
-        
-        Grunddaten enthalten im allgemeinen keine würfelrelevanten Werte."""
-        return self.daten[1][_(u"Grunddaten")]
-    
-    # Daten laden
-    def ladeKampfwerte(self): 
-        """Lade die Kampfrelevanten Werte des Charakters."""
-        return self.daten[4][_(u"Kampfwerte")]
-    def ladeAusruestung(self): 
-        """Lade die Ausrüstung des Charakters."""
-        return self.daten[3][_(u"Ausrüstung")]
-    def ladeBeschreibung(self): 
-        return self.ladeGrunddaten()[_(u"Beschreibung")]
-    def ladeHerkunft(self): 
-        return self.ladeGrunddaten()[_(u"Herkunft")]
-    def ladeRegion(self): 
-        return self.herkunft[_(u"Region")]
-    def ladeSprache(self): 
-        return self.herkunft[_(u"Sprache")]
-    def ladeStimmung(self): 
-        return self.ladeGrunddaten()[_(u"Stimmung")]
-    def ladeWerte(self): 
-        return self.daten[2][_(u"Werte")]
-    def ladeEigenschaften(self): 
-        return self.werte[0][_(u"Eigenschaften")]
-    def ladeFertigkeiten(self): 
-        return self.werte[1][_(u"Fertigkeiten")]
-    def ladeSchutz(self): 
-        return self.kampfwerte[_(u"Hauptrüstung")][_("Schutz")]
-    
-    # Daten in das dict speichern
-    # Das ist nötig, weil sonst beim umschreiben der Attribute des charakter-objekts das strings im dict nicht geändert wird (nur die Attribute werden umgeleitet - Strings sind nicht mutable. 
-    def speichereKampfwerte(self, daten): 
-        """Speichere die Kampfrelevanten Werte des Charakters."""
-        self.daten[4][_(u"Kampfwerte")] = daten
-    def speichereAusruestung(self, daten): 
-        """Speichere die Ausrüstung des Charakters."""
-        self.daten[3][_(u"Ausrüstung")] = daten
-    def speichereBeschreibung(self, daten): 
-        self.ladeGrunddaten()[_(u"Beschreibung")] = daten
-    def speichereHerkunft(self, daten): 
-        self.ladeGrunddaten()[_(u"Herkunft")] = daten
-    def speichereRegion(self, daten): 
-        self.herkunft[_(u"Region")] = daten
-    def speichereSprache(self, daten): 
-        self.herkunft[_(u"Sprache")] = daten
-    def speichereStimmung(self, daten): 
-        self.ladeGrunddaten()[_(u"Stimmung")] = daten
-    def speichereWerte(self, daten): 
-        self.daten[2][_(u"Werte")] = daten
-    def speichereEigenschaften(self, daten): 
-        self.werte[0][_(u"Eigenschaften")] = daten
-    def speichereFertigkeiten(self, daten): 
-        self.werte[1][_(u"Fertigkeiten")] = daten
-    def speichereSchutz(self, daten): 
-        self.kampfwerte[_(u"Hauptrüstung")][_("Schutz")] = daten
-    def speichereName(self, daten): 
-        self.daten[0][_("Name")] = daten
-    
-    def basic_data_yaml(self):
-        return self.leerer_charakterbogen_yaml()
-    
-    def leerer_charakterbogen_yaml(self): 
-        """@return: Den grundlegenden Charakterbogen. 
-        
-        Ideen: 
-            - Immer das letzte Element in der Liste kann für Daten des Programms aufbehalten werden. 
-        """
-        
-    	return """- Name: " "
-- Grunddaten: 
-    Beschreibung: " "
-    Herkunft: 
-        Sprache: Esperanto
-        Region: " "
-    Stimmung: ' '
-- Werte:
-    - Eigenschaften: 
-        Geschicklichkeit: &id003
-          Zahlenwert: 13
-    - Fertigkeiten: 
-        Nahkampf: &id001
-          Zahlenwert: 12
-          Grundwert: 12
-          Passende Eigenschaften: 
-          - *id003
-    - Berufe: 
-        Mensch: 
-            Zahlenwert: 9
-            Grundwert: 9
-    - Merkmale: {}
-- Ausrüstung: 
-    Waffen:
-      Waffenlos: &id002
-        Name: Iron knuckles
-        Schaden: 1
-    Rüestung: 
-        Stoffkleidung: &hauptruestung
-            Name: Simple garb