changeset 171:ff48c2741fe7 beta

Traipse Beta 'OpenRPG' {091210-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Beta) New Features: Added Bookmarks Added 'boot' command to remote admin Added confirmation window for sent nodes Minor changes to allow for portability to an OpenSUSE linux OS Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Zoom Mouse plugin added Images added to Plugin UI Switching to Element Tree Map efficiency, from FlexiRPG Added Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) Portable Mercurial Tip of the Day added, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added Added 7th Sea die roller method; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added Added new vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Includes support for Mythos roller. Fixes: Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fixed Whiteboard ID to prevent random line or text deleting. Modified ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and no reactive settings when Ok is pressed.
author sirebral
date Thu, 10 Dec 2009 22:30:40 -0600
parents e4a803df4c88
children 8834425a85b0
files orpg/chat/chatwnd.py orpg/dieroller/HOWTO.txt orpg/dieroller/__init__.py orpg/dieroller/base.py orpg/dieroller/d20.py orpg/dieroller/die.py orpg/dieroller/dieroller.txt orpg/dieroller/gurps.py orpg/dieroller/hackmaster.py orpg/dieroller/hero.py orpg/dieroller/mythos.py orpg/dieroller/rollers/__init__.py orpg/dieroller/rollers/alternity.py orpg/dieroller/rollers/d20.py orpg/dieroller/rollers/gurps.py orpg/dieroller/rollers/hackmaster.py orpg/dieroller/rollers/hero.py orpg/dieroller/rollers/mythos.py orpg/dieroller/rollers/runequest.py orpg/dieroller/rollers/savage.py orpg/dieroller/rollers/shadowrun.py orpg/dieroller/rollers/sr4.py orpg/dieroller/rollers/srex.py orpg/dieroller/rollers/std.py orpg/dieroller/rollers/trinity.py orpg/dieroller/rollers/wod.py orpg/dieroller/rollers/wodex.py orpg/dieroller/runequest.py orpg/dieroller/savage.py orpg/dieroller/shadowrun.py orpg/dieroller/sr4.py orpg/dieroller/srex.py orpg/dieroller/trinity.py orpg/dieroller/utils.py orpg/dieroller/wod.py orpg/dieroller/wodex.py orpg/main.py orpg/orpg_version.py orpg/templates/feature.xml orpg/templates/nodes/4e_char_sheet.xml orpg/tools/orpg_settings.py orpg/tools/predTextCtrl.py plugins/xxheroinit.py
diffstat 43 files changed, 4819 insertions(+), 5067 deletions(-) [+]
line wrap: on
line diff
--- a/orpg/chat/chatwnd.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/chat/chatwnd.py	Thu Dec 10 22:30:40 2009 -0600
@@ -1792,10 +1792,12 @@
             try: newstr = component.get('DiceManager').proccessRoll(newstr)
             except: pass
             if qmode == 1:
-                s = s.replace("[" + matches[i] + "]", "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
+                s = s.replace("[" + matches[i] + "]", 
+                            "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
             elif qmode == 2:
                 s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
-            else: s = s.replace("[" + matches[i] + "]", "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
+            else: s = s.replace("[" + matches[i] + "]", 
+                            "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
         return s
     
     def PraseUnknowns(self, s):
@@ -1848,14 +1850,11 @@
         i = 0
         rs = s[:]
         for c in s:
-            if c == "<":
-                in_tag += 1
+            if c == "<": in_tag += 1
             elif c == ">":
-                if in_tag:
-                    in_tag -= 1
+                if in_tag: in_tag -= 1
             elif c == '"':
-                if in_tag:
-                    rs = rs[:i] + "'" + rs[i+1:]
+                if in_tag: rs = rs[:i] + "'" + rs[i+1:]
             i += 1
         return rs
 
@@ -1896,8 +1895,12 @@
         ab_list = ab.findall('stat'); pc_stats = {}
 
         for ability in ab_list:
-            pc_stats[ability.get('name')] = ( str(ability.get('base')), str((int(ability.get('base'))-10)/2) )
-            pc_stats[ability.get('abbr')] = ( str(ability.get('base')), str((int(ability.get('base'))-10)/2) )
+            pc_stats[ability.get('name')] = ( 
+                    str(ability.get('base')), 
+                    str((int(ability.get('base'))-10)/2) )
+            pc_stats[ability.get('abbr')] = ( 
+                    str(ability.get('base')), 
+                    str((int(ability.get('base'))-10)/2) )
 
         if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
         else: ab = node.find('saves')
@@ -1981,7 +1984,30 @@
         reg = re.compile("(!!(.*?)!!)")
         matches = reg.findall(s)
         for i in xrange(0,len(matches)):
-            newstr = txt = '!@' + node.get('map') + '::' + matches[i][1] + '@!'
+            tree_map = node.get('map') + '::' + matches[i][1]
+            newstr = '!@'+ tree_map +'@!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.ParseNode(s)
+            s = self.ParseParent(s, tree_map)
+        return s
+
+    def ParseParent(self, s, tree_map):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        reg = re.compile("(!#(.*?)#!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            ## Build the new tree_map
+            new_map = tree_map.split('::')
+            del new_map[len(new_map)-1]
+            parent_map = matches[i][1].split('::')
+            ## Find an index or use 1 for ease of use.
+            try: index = new_map.index(parent_map[0])
+            except: index = 1
+            ## Just replace the old tree_map from the index.
+            new_map[index:len(new_map)] = parent_map
+            newstr = '::'.join(new_map)
+            newstr = '!@'+ newstr +'@!'
             s = s.replace(matches[i][0], newstr, 1)
             s = self.ParseNode(s)
         return s
--- a/orpg/dieroller/HOWTO.txt	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-HOW TO CREATE A NEW DIE ROLLER
-
-So you want a make a new roller or add a new option? here's a short guide.
-
-
-Step 1:  Create a new die roller sub class.
-
-You need to derive a new die roller class from an existing die roller class.  
-Most likely, this will be the std die roller class. 
-
-The basics would look like this:
-
-class new_roller(std):
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        .....
-
-    ....
-
-Step 2: Implement new methods and/or override existing ones.
-
-Now, you just need to implement any new die options and override any 
-existing ones that you want to act differently.  The most common options 
-to override are the sum and __str__ functions.  Sum is used to determine 
-the result of the rolls and __str__ is used to display the results in 
-a user friendly string.
-
-For example:
-
-class new_roller(std):
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        .....
-
-    def myoption(self,param):
-        ....
-
-    def sum(self):
-        ....
-
-    def __str__(self):
-        ....
-
-REMEMBER!
-Always return an instance of your die roller for each option expect str and sum.
-
-
-Step 3:
-
-Modify Utils.py
-
-You need to make some minor modifications to utils.py to facilitate 
-your new roller.  You need to a) add an import call for your roller, 
-and b) add your roller to the list of available rollers. 
-
-For example:
-
-from die import *
-# add addtional rollers here
-from myroller import *
-....
-
-rollers = ['std','wod','d20','myroller']
-
-Step 4:  You're done! 
-
-Test it and make sure it works.  When you think its done, send it to 
-the openrpg developers and they might include it in future releases.
-
--Chris Davis
-
-
--- a/orpg/dieroller/__init__.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-__all__ = ['dice', 'rollers', 'die', 'd20', 'std', 'hackmaster', 'hero', 'shadowrun', 'sr4', 'srex', 'utils', 'wod', 'wodex', 'utils']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/base.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,465 @@
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#        openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: die.py
+# Author: Andrew Bennett
+# Maintainer:
+# Version:
+#   $Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $
+#
+# Description: This class is used to make working with dice easier
+#
+
+__version__ = "$Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $"
+
+
+import random
+import UserList
+import copy
+#import string
+
+class die_base(UserList.UserList):
+    name = None
+
+    def __init__(self,source = []):
+        if isinstance(source, (int, float, basestring)):
+            s = []
+            s.append(di(source))
+        else:
+            s = source
+        UserList.UserList.__init__(self,s)
+
+
+    def sum(self):
+        s = 0
+        for a in self.data:
+            s += int(a)
+        return s
+
+    def __lshift__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            o = other
+        elif hasattr(other,"sum"):
+            o = other.sum()
+        else:
+            return None
+
+        result = []
+        for die in self:
+            if die < o:
+                result.append(die)
+        return self.__class__(result)
+
+    def __rshift__(self,other):
+
+        if type(other) == type(3) or type(other) == type(3.0):
+            o = other
+        elif hasattr(other,"sum"):
+            o = other.sum()
+        else:
+            return None
+
+        result = []
+        for die in self:
+            if die > o:
+                result.append(die)
+        return self.__class__(result)
+
+    def __rlshift__(self,other):
+        return self.__rshift__(other)
+
+    def __rrshift__(self,other):
+        return self.__lshift__(other)
+
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            myStr += "] = (" + str(self.sum()) + ")"
+        else:
+            myStr = "[] = (0)"
+        return myStr
+
+    def __lt__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() < other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() < other.sum())
+        else:
+            return UserList.UserList.__lt__(self,other)
+
+    def __le__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() <= other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() <= other.sum())
+        else:
+            return UserList.UserList.__le__(self,other)
+
+    def __eq__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() == other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() == other.sum())
+        else:
+            return UserList.UserList.__eq__(self,other)
+
+    def __ne__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() != other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() != other.sum())
+        else:
+            return UserList.UserList.__ne__(self,other)
+
+    def __gt__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() > other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() > other.sum())
+        else:
+            return UserList.UserList.__gt__(self,other)
+
+    def __ge__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return (self.sum() >= other)
+        elif hasattr(other,"sum"):
+            return  (self.sum() >= other.sum())
+        else:
+            return UserList.UserList.__ge__(self,other)
+
+    def __cmp__(self,other):
+        #  this function included for backwards compatibility
+        #  As of 2.1, lists implement the "rich comparison"
+        #  methods overloaded above.
+        if type(other) == type(3) or type(other) == type(3.0):
+            return cmp(self.sum(), other)
+        elif hasattr(other,"sum"):
+            return  cmp(self.sum(), other.sum())
+        else:
+            return UserList.UserList.__cmp__(self,other)
+
+
+    def __rcmp__(self,other):
+        return self.__cmp__(other)
+
+    def __add__(self,other):
+        mycopy = copy.deepcopy(self)
+        if type(other) == type(3) or type(other) == type(3.0):
+            #if other < 0:
+            #    return self.__sub__(-other)
+            #other = [di(other,other)]
+            other = [static_di(other)]
+            #return self.sum() + other
+
+        elif type(other) == type("test"):
+            return self
+        mycopy.extend(other)
+        #result = UserList.UserList.__add__(mycopy,other)
+        return mycopy
+
+    def __iadd__(self,other):
+        return self.__add__(other)
+
+    def __radd__(self,other):
+        mycopy = copy.deepcopy(self)
+        if type(other) == type(3) or type(other) == type(3.0):
+            new_die = di(0)
+            new_die.set_value(other)
+            other = new_die
+        mycopy.insert(0,other)
+        return mycopy
+
+    def __int__(self):
+        return self.sum()
+
+    def __sub__(self,other):
+        mycopy = copy.deepcopy(self)
+        if type(other) == type(3) or type(other) == type(3.0):
+            neg_die = static_di(-other)
+            #neg_die.set_value(-other)
+            other = [neg_die]
+            #return self.sum() - other
+        else:
+            other = -other
+        mycopy.extend(other)
+        return mycopy
+
+    def __rsub__(self,other):
+        mycopy = -copy.deepcopy(self)
+        #print type(other)
+        if type(other) == type(3) or type(other) == type(3.0):
+            new_die = di(0)
+            new_die.set_value(other)
+            other = new_die
+        mycopy.insert(0,other)
+        return mycopy
+
+    def __isub__(self,other):
+        return self.__sub__(other)
+
+    def __mul__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.sum() * other
+        elif hasattr(other,"sum"):
+            return other.sum() * self.sum()
+        else:
+            return UserList.UserList.__mul__(self,other)
+
+    def __rmul__(self,other):
+        return self.__mul__(other)
+
+    def __div__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return float(self.sum()) / other
+        elif hasattr(other,"sum"):
+            return  float(self.sum()) / other.sum()
+        else:
+            return UserList.UserList.__div__(self,other)
+
+    def __rdiv__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return other / float(self.sum())
+        elif hasattr(other,"sum"):
+            return  other.sum() / float(self.sum())
+        else:
+            return UserList.UserList.__rdiv__(self,other)
+
+    def __mod__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.sum()%other
+        elif hasattr(other,"sum"):
+            return  self.sum() % other.sum()
+        else:
+            return UserList.UserList.__mod__(self,other)
+
+    def __rmod__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return other % self.sum()
+        elif hasattr(other,"sum"):
+            return  other.sum() % self.sum()
+        else:
+            return UserList.UserList.__rmod__(self,other)
+
+    def __neg__(self):
+        for i in range(len(self.data)):
+            self.data[i] = -self.data[i]
+        return self
+
+    def __pos__(self):
+        for i in range(len(self.data)):
+            self.data[i] = +self.data[i]
+        return self
+
+    def __abs__(self):
+        for i in range(len(self.data)):
+            self.data[i] = abs(self.data[i])
+        return self
+        #return abs(self.sum())
+
+    def __pow__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.sum() ** other
+        elif hasattr(other,"sum"):
+            return  self.sum() ** other.sum()
+        else:
+            return UserList.UserList.__pow__(self,other)
+
+
+    def __rpow__(self,other):
+        #  We're overloading exponentiation of ints to create "other" number of dice
+
+        if other >= 1:
+            result = self.__class__(self[0].sides)
+            for t in range(other-1):
+                result+=self.__class__(self[0].sides)
+        else:
+            result = None
+
+        return result
+
+### di class to handle actual dice
+
+class di:
+    def __init__(self,sides,min=1):
+        self.sides = sides
+        self.history = None
+        self.value = None
+        self.target = None
+        self.roll(min)
+
+    def __str__(self):
+        if len(self.history) > 1:
+            return str(self.history)
+        else:
+            return str(self.value)
+
+    def __neg__(self):
+        self.value = -self.value
+        for i in range(len(self.history)):
+            self.history[i] = -self.history[i]
+        return self
+
+    def __pos__(self):
+        self.value = +self.value
+        for i in range(len(self.history)):
+            self.history[i] = +self.history[i]
+        return self
+
+    def __abs__(self):
+        self.value = abs(self.value)
+        for i in range(len(self.history)):
+            self.history[i] = abs(self.history[i])
+        return self
+
+    def __repr__(self):
+        if len(self.history) > 1:
+            return str(self.history)
+        else:
+            return str(self.value)
+
+    def __int__(self):
+        return self.value
+
+
+    def __lt__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value < other
+        elif hasattr(other,"value"):
+            return self.value < other.value
+        else:
+            return self < other
+
+    def __le__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value <= other
+        elif hasattr(other,"value"):
+            return self.value <= other.value
+        else:
+            return self <= other
+
+    def __eq__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value == other
+        elif hasattr(other,"value"):
+            return self.value == other.value
+        else:
+            return self == other
+
+    def __ne__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value != other
+        elif hasattr(other,"value"):
+            return self.value != other.value
+        else:
+            return self != other
+
+    def __gt__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value > other
+        elif hasattr(other,"value"):
+            return self.value > other.value
+        else:
+            return self > other
+
+    def __ge__(self,other):
+        if type(other) == type(3) or type(other) == type(3.0):
+            return self.value >= other
+        elif hasattr(other,"value"):
+            return self.value >= other.value
+        else:
+            return self >= other
+
+    def __cmp__(self,other):
+        #  this function included for backwards compatibility
+#  As of 2.1, lists implement the "rich comparison"
+#  methods overloaded above.
+        if type(other) == type(3) or type(other) == type(3.0):
+            return cmp(self.value, other)
+        elif hasattr(other,"value"):
+            return cmp(self.value, other.value)
+        else:
+            return cmp(self,other)
+
+    def roll(self,min=1):
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
+            self.value = random.randint(-1, 1)
+        else:
+            #self.value = random.randint(min, self.sides)
+            self.value = int(random.uniform(min, self.sides+1))
+        self.history = []
+        self.history.append(self.value)
+
+    def extraroll(self):
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
+            result = random.randint(-1, 1)
+        else:
+            #result = random.randint(1, self.sides)
+            result = int(random.uniform(1,self.sides+1))
+
+        self.value += result
+        self.history.append(result)
+
+    def lastroll(self):
+        return self.history[len(self.history)-1]
+
+    def set_value(self,value):
+        self.value = value
+        self.history = []
+        self.history.append(self.value)
+
+    def modify(self,mod):
+        self.value += mod
+        self.history.append(mod)
+
+    def gethistory(self):
+        return self.history[:]
+
+class static_di(di):
+    def __init__(self,value):
+        di.__init__(self,value,value)
+        self.set_value(value)
+
+class DieRollers(object):
+    _rollers = {}
+    def __new__(cls):
+        it = cls.__dict__.get("__it__")
+        if it is not None:
+            return it
+        cls.__it__ = it = object.__new__(cls)
+        return it
+
+    def keys(self):
+        return self._rollers.keys()
+
+    def register(self, roller):
+        if not self._rollers.has_key(roller.name):
+            self._rollers[roller.name] = roller
+
+    def __getitem__(self, roller_name):
+        return self._rollers.get(roller_name, None)
+
+    def __setitem__(self, *args):
+        raise AttributeError
+
+die_rollers = DieRollers()
\ No newline at end of file
--- a/orpg/dieroller/d20.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: d20.py
-# Author: OpenRPG Dev Team
-# Maintainer:
-# Version:
-#   $Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $
-#
-# Description: d20 die roller
-#
-from die import *
-
-__version__ = "$Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $"
-
-# d20 stands for "d20 system" not 20 sided die :)
-
-class d20(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-# these methods return new die objects for specific options
-
-    
-    def attack(self,AC,mod,critical):
-        return d20attack(self,AC,mod,critical)
-
-    
-    def dc(self,DC,mod):
-        return d20dc(self,DC,mod)
-
-class d20dc(std):
-    
-    def __init__(self,source=[],DC=10,mod=0):
-        std.__init__(self,source)
-        self.DC = DC
-        self.mod = mod
-        self.append(static_di(mod))
-
-    
-    def is_success(self):
-        return ((self.sum() >= self.DC or self.data[0] == 20) and self.data[0] != 1)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-
-        myStr += " vs DC " + str(self.DC)
-
-        if self.is_success():
-            myStr += " Success!"
-        else:
-            myStr += " Failure!"
-
-        return myStr
-
-
-class d20attack(std):
-    
-    def __init__(self,source=[],AC=10,mod=0,critical=20):
-        std.__init__(self,source)
-        self.mod = mod
-        self.critical = critical
-        self.AC = AC
-        self.append(static_di(mod))
-        self.critical_check()
-
-    
-    def attack(AC=10,mod=0,critical=20):
-        self.mod = mod
-        self.critical = critical
-        self.AC = AC
-
-    
-    def critical_check(self):
-        self.critical_result = 0
-        self.critical_roll = 0
-        if self.data[0] >= self.critical and self.is_hit():
-            self.critical_roll = die_base(20) + self.mod
-            if self.critical_roll.sum() >= self.AC:
-                self.critical_result = 1
-
-    
-    def is_critical(self):
-        return self.critical_result
-
-    
-    def is_hit(self):
-        return ((self.sum() >= self.AC or self.data[0] == 20) and self.data[0] != 1)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-
-        myStr += " vs AC " + str(self.AC)
-
-        if self.is_critical():
-            myStr += " Critical"
-
-        if self.is_hit():
-            myStr += " Hit!"
-        else:
-            myStr += " Miss!"
-
-        return myStr
--- a/orpg/dieroller/die.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,503 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#        openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: die.py
-# Author: Andrew Bennett
-# Maintainer:
-# Version:
-#   $Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $
-#
-# Description: This class is used to make working with dice easier
-#
-
-__version__ = "$Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $"
-
-
-import random
-import UserList
-import copy
-#import string
-
-class die_base(UserList.UserList):
-
-    def __init__(self,source = []):
-        if isinstance(source, (int, float, basestring)):
-            s = []
-            s.append(di(source))
-        else: s = source
-        UserList.UserList.__init__(self,s)
-
-    def sum(self):
-        s = 0
-        for a in self.data:
-            s += int(a)
-        return s
-
-    def __lshift__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): o = other
-        elif hasattr(other,"sum"): o = other.sum()
-        else: return None
-        result = []
-        for die in self:
-            if die < o: result.append(die)
-        return self.__class__(result)
-
-    def __rshift__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): o = other
-        elif hasattr(other,"sum"): o = other.sum()
-        else: return None
-        result = []
-        for die in self:
-            if die > o: result.append(die)
-        return self.__class__(result)
-
-    def __rlshift__(self,other):
-        return self.__rshift__(other)
-
-    def __rrshift__(self,other):
-        return self.__lshift__(other)
-
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            myStr += "] = (" + str(self.sum()) + ")"
-        else: myStr = "[] = (0)"
-        return myStr
-
-    def __lt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() < other)
-        elif hasattr(other,"sum"): return  (self.sum() < other.sum())
-        else: return UserList.UserList.__lt__(self,other)
-
-    def __le__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() <= other)
-        elif hasattr(other,"sum"): return  (self.sum() <= other.sum())
-        else: return UserList.UserList.__le__(self,other)
-
-    def __eq__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() == other)
-        elif hasattr(other,"sum"): return  (self.sum() == other.sum())
-        else: return UserList.UserList.__eq__(self,other)
-
-    def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() != other)
-        elif hasattr(other,"sum"):return  (self.sum() != other.sum())
-        else: return UserList.UserList.__ne__(self,other)
-
-    def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() > other)
-        elif hasattr(other,"sum"): return  (self.sum() > other.sum())
-        else: return UserList.UserList.__gt__(self,other)
-
-    def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() >= other)
-        elif hasattr(other,"sum"): return  (self.sum() >= other.sum())
-        else: return UserList.UserList.__ge__(self,other)
-
-    def __cmp__(self,other):
-        #  this function included for backwards compatibility
-        #  As of 2.1, lists implement the "rich comparison"
-        #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0): return cmp(self.sum(), other)
-        elif hasattr(other,"sum"): return  cmp(self.sum(), other.sum())
-        else: return UserList.UserList.__cmp__(self,other)
-
-    def __rcmp__(self,other):
-        return self.__cmp__(other)
-
-    def __add__(self,other):
-        mycopy = copy.deepcopy(self)
-        if type(other) == type(3) or type(other) == type(3.0): other = [static_di(other)]
-        elif type(other) == type("test"): return self
-        mycopy.extend(other)
-        return mycopy
-
-    def __iadd__(self,other):
-        return self.__add__(other)
-
-    def __radd__(self,other):
-        mycopy = copy.deepcopy(self)
-        if type(other) == type(3) or type(other) == type(3.0):
-            new_die = di(0)
-            new_die.set_value(other)
-            other = new_die
-        mycopy.insert(0,other)
-        return mycopy
-
-    def __int__(self):
-        return self.sum()
-
-    def __sub__(self,other):
-        mycopy = copy.deepcopy(self)
-        if type(other) == type(3) or type(other) == type(3.0):
-            neg_die = static_di(-other)
-            other = [neg_die]
-        else: other = -other
-        mycopy.extend(other)
-        return mycopy
-
-    def __rsub__(self,other):
-        mycopy = -copy.deepcopy(self)
-        if type(other) == type(3) or type(other) == type(3.0):
-            new_die = di(0)
-            new_die.set_value(other)
-            other = new_die
-        mycopy.insert(0,other)
-        return mycopy
-
-    def __isub__(self,other):
-        return self.__sub__(other)
-
-    def __mul__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return self.sum() * other
-        elif hasattr(other,"sum"): return other.sum() * self.sum()
-        else: return UserList.UserList.__mul__(self,other)
-
-    
-    def __rmul__(self,other):
-        return self.__mul__(other)
-
-    
-    def __div__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return float(self.sum()) / other
-        elif hasattr(other,"sum"): return  float(self.sum()) / other.sum()
-        else: return UserList.UserList.__div__(self,other)
-
-    
-    def __rdiv__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0): return other / float(self.sum())
-        elif hasattr(other,"sum"): return  other.sum() / float(self.sum())
-        else: return UserList.UserList.__rdiv__(self,other)
-
-    
-    def __mod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum()%other
-        elif hasattr(other,"sum"):
-            return  self.sum() % other.sum()
-        else:
-            return UserList.UserList.__mod__(self,other)
-
-    
-    def __rmod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return other % self.sum()
-        elif hasattr(other,"sum"):
-            return  other.sum() % self.sum()
-        else:
-            return UserList.UserList.__rmod__(self,other)
-
-    
-    def __neg__(self):
-        for i in range(len(self.data)):
-            self.data[i] = -self.data[i]
-        return self
-
-    
-    def __pos__(self):
-        for i in range(len(self.data)):
-            self.data[i] = +self.data[i]
-        return self
-
-    
-    def __abs__(self):
-        for i in range(len(self.data)):
-            self.data[i] = abs(self.data[i])
-        return self
-        #return abs(self.sum())
-
-    
-    def __pow__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum() ** other
-        elif hasattr(other,"sum"):
-            return  self.sum() ** other.sum()
-        else:
-            return UserList.UserList.__pow__(self,other)
-
-
-    
-    def __rpow__(self,other):
-        #  We're overloading exponentiation of ints to create "other" number of dice
-
-        if other >= 1:
-            result = self.__class__(self[0].sides)
-            for t in range(other-1):
-                result+=self.__class__(self[0].sides)
-        else:
-            result = None
-
-        return result
-
-### di class to handle actual dice
-
-class di:
-    
-    def __init__(self,sides,min=1):
-        self.sides = sides
-        self.history = None
-        self.value = None
-        self.target = None
-        self.roll(min)
-
-    
-    def __str__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
-
-    
-    def __neg__(self):
-        self.value = -self.value
-        for i in range(len(self.history)):
-            self.history[i] = -self.history[i]
-        return self
-
-    
-    def __pos__(self):
-        self.value = +self.value
-        for i in range(len(self.history)):
-            self.history[i] = +self.history[i]
-        return self
-
-    
-    def __abs__(self):
-        self.value = abs(self.value)
-        for i in range(len(self.history)):
-            self.history[i] = abs(self.history[i])
-        return self
-
-    
-    def __repr__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
-
-    
-    def __int__(self):
-        return self.value
-
-
-    
-    def __lt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value < other
-        elif hasattr(other,"value"):
-            return self.value < other.value
-        else:
-            return self < other
-
-    
-    def __le__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value <= other
-        elif hasattr(other,"value"):
-            return self.value <= other.value
-        else:
-            return self <= other
-
-    
-    def __eq__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value == other
-        elif hasattr(other,"value"):
-            return self.value == other.value
-        else:
-            return self == other
-
-    
-    def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value != other
-        elif hasattr(other,"value"):
-            return self.value != other.value
-        else:
-            return self != other
-
-    
-    def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value > other
-        elif hasattr(other,"value"):
-            return self.value > other.value
-        else:
-            return self > other
-
-    
-    def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value >= other
-        elif hasattr(other,"value"):
-            return self.value >= other.value
-        else:
-            return self >= other
-
-    
-    def __cmp__(self,other):
-        #  this function included for backwards compatibility
-        #  As of 2.1, lists implement the "rich comparison"
-        #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0):
-            return cmp(self.value, other)
-        elif hasattr(other,"value"):
-            return cmp(self.value, other.value)
-        else:
-            return cmp(self,other)
-
-    
-    def roll(self,min=1):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            self.value = random.randint(-1, 1)
-        else:
-            #self.value = random.randint(min, self.sides)
-            self.value = int(random.uniform(min, self.sides+1))
-        self.history = []
-        self.history.append(self.value)
-
-    
-    def extraroll(self):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            result = random.randint(-1, 1)
-        else:
-            #result = random.randint(1, self.sides)
-            result = int(random.uniform(1,self.sides+1))
-
-        self.value += result
-        self.history.append(result)
-
-    
-    def lastroll(self):
-        return self.history[len(self.history)-1]
-
-    
-    def set_value(self,value):
-        self.value = value
-        self.history = []
-        self.history.append(self.value)
-
-    
-    def modify(self,mod):
-        self.value += mod
-        self.history.append(mod)
-
-    
-    def gethistory(self):
-        return self.history[:]
-
-class static_di(di):
-    
-    def __init__(self,value):
-        di.__init__(self,value,value)
-        self.set_value(value)
-
-
-class std(die_base):
-    
-    def __init__(self,source=[]):
-        die_base.__init__(self,source)
-
-    #  Examples of adding member functions through inheritance.
-
-    
-    def ascending(self):
-        result = self[:]
-        result.sort()
-        return result
-
-    
-    def descending(self):
-        result = self[:]
-        result.sort()
-        result.reverse()
-        return result
-
-    
-    def takeHighest(self,num_dice):
-        return self.descending()[:num_dice]
-
-    
-    def takeLowest(self,num_dice):
-        return self.ascending()[:num_dice]
-
-    
-    def extra(self,num):
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() >= num:
-                self.data[i].extraroll()
-        return self
-
-    
-    def open(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() >= num:
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.open(num)
-
-    
-    def minroll(self,min):
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() < min:
-                self.data[i].roll(min)
-        return self
-
-    
-    def each(self,mod):
-        mod = int(mod)
-        for i in range(len(self.data)):
-            self.data[i].modify(mod)
-        return self
-
-
-    
-    def vs(self, target):
-        for dn in self.data:
-            dn.target = target
-        return self
-
-
-    ## If we are testing against a saving throw, we check for
-    ## greater than or equal to against the target value and
-    ## we only return the number of successful saves.  A negative
-    ## value will never be generated.
-    
-    def sum(self):
-        retValue = 0
-        for dn in self.data:
-            setValue = reduce( lambda x, y : int(x)+int(y), dn.history )
-            if dn.target:
-                if setValue >= dn.target:
-                    retValue += 1
-
-            else:
-                retValue += setValue
-
-        return retValue
--- a/orpg/dieroller/dieroller.txt	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-The New Dicing System:  A Proposal for OpenRPG
-----------------------------------------------
-
-The current dice system for OpenRPG has several limitations.  Foremost
-among these are the fact that adding a new, non-standard dicing mechanism
-requires editing of the basic dice code.  There are several secondary 
-limitations, such as the fact that while the dice system can handle math,
-it cannot be used as a calculator -- it will not allow expressions that do
-not involve dice.
-
-This proposal is for a new dicing system to replace the current one in
-OpenRPG.  Since the dicing system is something that users will interact
-with frequently, a new system needs to be considered carefully.  This
-document attempts to describe the new dicing system so that such 
-consideration can be given to it.  It is expected that this document will
-grow and change as it is scrutinized.
-
-
-Design goals for this dicing system:
-
- 1. Should be easy for new users to get started with, based on knowing
-    standard RPG dice notation (NdX) and basic math.
-
- 2. Should, as far as practical, maintain compatibility with existing
-    character sheets, etc., that use the current dice system.
-
- 3. Should allow users to create new dice types and new ways of 
-    counting dice.  Ideally, this should not require programming, except
-    in exceptional cases.
-
- 4. The dice system should be usable for doing basic math that does
-    not involve dice.
-
- 5. The dice system should be able to handle most current RPG dicing
-    systems.
-
-Things this dicing system is designed to NOT do:
-
- 1. Be a programming language.  There are no facilities in it for 
-    user input, output formatting, loops, if-then-else, or similar
-    things.  If these are desired for something involving dice, an
-    appropriate node and nodehandler can be created.
-
- 2. Handle all theoretically possible dicing systems without the
-    need for programming plugins.  First off, this is impossible.  
-    Second, even making an attempt to would require supporting 
-    dicing methods that don't actually turn up in any real game.
-
- 3. Handle floating-point math.  I don't know of any systems that
-    use it in their dice schemes right now.  If there are some,
-    we might have to consider adding it.
-
-
-Syntax Specification 
-
-What follows is a BNF specification for the proposed dicing system, with
-explanatory text interleaved.  At the end of this document is a copy of
-the BNF with no explanations, for those who would like to look at it "all
-together".  Note that BNF describes only syntax, and not semantics; thus,
-while anything generated with this grammar should be syntactically correct,
-that doesn't mean it will make sense or be allowed.
-
-
-dice string ::= <expression>
-                <expression> of <comparison> | <comparison>
-
-This is the top level.  The major thing of note here is that comparisons
-only occur at this level.  This is intentional; the result of a comparison
-is a boolean true/false flag rather than a number.  Thus, it makes no 
-sense to allow people to perform further numerical operations on the 
-result of a comparison.  Systems where dice are triggered by the results 
-of other dice are left for the realm of plugins.
-
-                
-comparison ::= <expression> <relation> <expression>
-
-expression ::= <factor> | <factor> <low-op> <factor>
-
-The separation into "low-op" and "high-op" of the operators is to allow
-order of operations to be handled more easily.  Syntactically, it's not
-really necessary, but it should be helpful in implementation.
-
-
-factor :: = <term> | <term> <high-op> <term> |
-            <multi-dice> | <multi-dice> <high-op> <term> |
-            <term> <high-op> <multi-dice>
-
-Here we start to hit some complication.  The intent of the different 
-entries for multi-dice is that we don't want to allow things like
-[3d6 each * 2d6 each].  We are *not* doing vector multiplication!
-The "expression" level doesn't have any such limitation on syntax; 
-things like [3d6 each + 2d6 each] we'll have to either think of a 
-logical way to handle, or disallow on a semantic level.  (Well... I 
-suppose it could be handled in the BNF, but I think it would get
-kind of messy.)
-
-
-term ::= <dice> | <unit>
-
-unit ::= <number> | ( <expression> )
-
-Dice are not considered a unit.  This means that things like [3d6d10] can't
-be done without using parentheses.  I consider that to be a win for 
-clarity.
-
-
-dice ::= <unit>d<unit> | <unit>d<name> | <dice> <flag> | lastroll
-
-The <name> entry here allows for user-created dice (in the syntax, at 
-least...).
-
-
-multi-dice ::= ( <dice>, <dice>+ ) |               # (1d6,1d8)
-               <dice> each |                       # 3d6 each
-               ( <expression> of <expression> ) |  # (3 of 2d6)
-               lastroll |                          # lastroll
-               <multi-dice> <flag>                 # (3 of 2d6) best 2
-
-"lastroll" by itself can be either dice or multi-dice.  I'm thinking that it
- 
-should be whatever type the last roll was.
-
-
-flag ::= reroll <condition> |          # repeats
-         reroll <slice> |              # once only
-         grow <condition> |            # reroll and add
-         shrink <condition> |          # reroll and subtract
-         drop <condition> |
-         drop <slice> |
-         take <condition> |
-         take <slice> |
-         <slice> |                     # implied "take"
-         <name> <condition> |          # user-created
-         <name>                        # user-created
-
-Technically, we don't need both "drop" and "take" -- one implies the 
-other.  However, having both should make the language easier to use.
-
-"reroll" will work differently depending on whether a condition or a 
-slice is given.  If a condition is given, it will reroll until none of
-the dice in the set meet the reroll condition (or until it hits a maximum
-allowed number of rerolls).  If a slice is given, it will reroll those
-dice once.  IMHO, this behavior makes the most sense.
-
-The <name> entries here are to allow for user-created flags.  Note that
-as I've specified things right now, a user-created flag can have a
- condition,
-but not a slice.  That's mostly because I couldn't think of a case where
-a slice would be useful... should we add it anyways?
-
-
-slice ::= highest | lowest | highest <number> | lowest <number>
-
-"highest" and "lowest" without a number are equivalent to doing them with
-1 as the number.  This is to simplify things like [4d6 drop lowest].
-
-
-condition ::= <relation> <unit>
-
-This is for conditions on flags.  Note that it can take a unit, so you could
-
-use dice in a condition; however, I think the unit should only be evaluated 
-
-once, to make things faster.  Anyone for repetitive evaluation?
-
-
-low-op ::= + | - | min | max
-
-"min" takes two values and returns the highest of them, and "max"
-returns the lowest of them.  This might seem counterintuitive, but
-it's meant to be used with dice, like so:
-
-  3d6 min 8   - always returns 8 or higher
-
-  3d6 max 15  - always returns 15 or lower
-
-I decided to put min and max as having the same precedence as + and -,
-because if they had higher precedence, then:
-
-  3d6+2 min 10 
-
-would be equivalent to 3d6+10.  (It would take the max of 2 and 10, then
-add that to 3d6).  One problem that does arise here is with multiplication 
-and division:  [1d6 min 5 * 2] will be equivalent to [1d6 min 10], since
-multiplication has higher precedence.  We may just want to warn people 
-that min and max can be screwy unless you parenthesize, unless someone can
-think of a better way to handle them.
-
-
-high-op ::= * | / | mod
-
-The / is integer division, of course, since we're doing integer math.  
-
-
-number ::= <digit>+ | -<digit>+
-
-Positive and negative numbers are allowed.  This means that, syntactically,
-[-2d-4] is legal.  Do we want to modify the BNF to disallow this, or handle
-it on a semantic level?
-
-
-name ::= <letter>[<letter>|<digit>]*
-
-We may want to expand to allow underscores and dashes in user-created names.
-
-
-
-letter ::= A-Z | a-z
-
-digit ::= 0-9
-
-relation ::= < | > | <= | >= | => | =< | = | ==
-
-
-
-Well, that's the BNF.  Again, at the end is a copy without all the running
-commentary.
-
-
-Thoughts on Implementation:
-
-First, I think a sort of "dice library" of common functions needs to be
-created.  This would include rolling a set of dice, getting the highest
-of a group of dice, growing and shrinking dice from a set based on 
-conditions, and so on.  These functions should be available for use by
-custom-written dice types.
-
-Next, that library should be used as a tool in implementing a dice-string
-interpreter.  That will require creating a parser for the dice-string 
-'language'.  This could be either a custom-written parser, or possibly
-one created with some of the Python parser generators.  A custom-written
-parser may take longer to do and be a bit more finicky to maintain, but
-it would remove a dependency from the code.
-
-User-created flags and dice types could be supported in two ways:
-
- - First, by allowing users to specify strings in the dice language
-   that the flags/expressions would expand to -- basically, allowing
-   dice macros.
-
- - Second, by adding hooks for python modules to be associated with
-   user-created dice or flag types.  This is likely to be the more
-   complicated of the two solutions, but it would also be more 
-   flexible.
-
-Personally, I think both are desirable -- the first, so that 
-non-programming users can create simple die and flag types.  The
-second, because by design, there are some things this dice system 
-just won't do.
-
-
-Further work needed:
-
- - specs for the "dice library"
-
- - specs on an interface for python modules meant to be dice and
-   flag types.
-
-----------------------------------------------------------------
-
-start ::= <expression> |
-          <comparison>
-
-comparison ::= <expression> <condition>
-
-expression ::= <term> | <term> <low-op> <factor>
-
-term ::= <factor> | <factor> <high-op> <unit>
-
-factor ::= <atom> | <dice_set>
-
-atom ::= <number> | ( <expression> )
-
-dice_set ::= <dice> <dice_set>, <dice> | <expr> of <dice> | <dice> each |
-             lastroll
-
-dice ::= <atom>d<atom> | <atom>d<name> | <dice> <flag>
-
-flag ::= reroll <condition> |
-         reroll <slice> |
-         grow <condition> |  
-         shrink <condition> |        
-         drop <condition> |
-         drop <slice> |
-         take <condition> |
-         take <slice> |
-         <slice> |         
-         <name> <condition> |
-	 <name> <slice> |
-         <name>
-
-slice ::= highest | lowest | highest <number> | lowest <number>
-
-condition ::= <relation> <unit>
-
-low-op ::= + | -
-
-high-op ::= * | / | mod| max | min
-
-number ::= <digit>+ | -<digit>+
-
-name ::= <letter>[<letter>|<digit>]*
-
-letter ::= A-Z | a-z
-
-digit ::= 0-9
-
-relation ::= < | > | <= | >= | => | =< | = | ==
-
--- a/orpg/dieroller/gurps.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,723 +0,0 @@
-#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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-# --
-#
-# File: gurps.py
-# Version:
-#   $Id: gurps.py,v 1.3
-#
-# Description: Modified Hero System die roller based on DJM and Heroman's Hero
-# dieroller
-#
-# GURPS is a trademark of Steve Jackson Games, and its rules and art are
-# copyrighted by Steve Jackson Games. All rights are reserved by Steve Jackson
-# Games. This game aid is the original creation of Naryt with help from Pyrandon
-# and is released for free distribution, and not for resale, under the
-# permissions granted in the Steve Jackson Games Online Policy.
-# http://www.sjgames.com/general/online_policy.html
-#
-# Errors should be reported to rpg@ormonds.net
-#
-# Changelog:
-# V 1.3  2007/03/23  Thomas M. Edwards <tmedwards@motoslave.net>
-#   Fixed gurpsskill, gurpsdefaultskill, and gurpssupernatural to correctly
-#   return a normal failure when the roll is 17 and the effective skill is 27+;
-#   previously, they would erroneously return a critical failure.  This fix also
-#   corrects the less serious issue whereby rolls of 17 and an effective skill
-#   of 17-26 would report "failure by X" instead of merely "failure", which is
-#   wrong as the only reason the roll failed was because a 17 was rolled, not
-#   because the roll exceeded the effective skill.
-# V 1.2 29 October 2006, added defaultskill (Rule of 20 [B344]), supernatural
-#   (Rule of 16 [B349]).  The frightcheck roll is now the actual Fright Check
-#   (with Rule of 14 [B360]) and a lookup oon the Fright Check Table if needed.
-#   The fightcheckfail roll is the old Fright Check Table lookup.
-#   Removes the Help roller as it was nothing but trouble, see
-#   http://openrpg.wrathof.com/repository/GURPS/GURPS_Roller_1.7.xml for help
-#   in using this roller.
-# V 1 Original gurps release 2006/05/28 00:00:00, modified crit_hit, crit_headblow, crit_miss, crit_unarm, spellfail, frightcheck and help_me
-#       Corrects numerous descriptions
-# v.1 original gurps release by Naryt 2005/10/17 16:34:00
-
-from die import *
-from time import time, clock
-import random
-
-__version__ = "$Id: gurps.py,v 1.5 2007/05/06 16:42:55 digitalxero Exp $"
-
-# gurps
-
-class gurps(std):
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-# these methods return new die objects for specific options
-
-# Original msk roll renamed to be easier to understand/remember
-    
-    def skill(self,skill,mod):
-        return gurpsskill(self,skill,mod)
-
-    
-    def defaultskill(self,stat,defaultlevel,mod):
-        return gurpsdefaultskill(self,stat,defaultlevel,mod)
-
-    
-    def supernatural(self,skill,resistance,mod):
-        return gurpssupernatural(self,skill,resistance,mod)
-
-    
-    def crit_hit(self):
-        return gurpscrit_hit(self)
-
-    
-    def crit_headblow(self):
-        return gurpscrit_headblow(self)
-
-    
-    def crit_miss(self):
-        return gurpscrit_miss(self)
-
-    
-    def crit_unarm(self):
-        return gurpscrit_unarm(self)
-
-    
-    def spellfail(self):
-        return gurpsspellfail(self)
-
-    
-    def frightcheck(self,level,mod):
-        return gurpsfrightcheck(self,level,mod)
-
-    
-    def frightcheckfail(self,mod):
-        return gurpsfrightcheckfail(self,mod)
-
-class gurpsskill(std):
-    
-    def __init__(self,source=[],skill=0,mod=0):
-        std.__init__(self,source)
-        self.skill = skill
-        self.mod = mod
-
-    
-    def is_success(self):
-        return (((self.sum()) <= self.skill+self.mod) and (self.sum() < 17))
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="]"
-        myStr += " = <b>" + str(self.sum()) + "</b>"
-        myStr += " vs <b>(" + str(self.skill+self.mod) + ")</b>"
-
-        Diff = abs((self.skill+self.mod) - self.sum())
-
-        if self.is_success():
-            if self.sum() == 3 or self.sum() == 4:
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
-            elif self.sum() == 5 and (self.skill+self.mod > 14):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
-            elif self.sum() == 6 and (self.skill+self.mod > 15):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
-        else:
-            if self.sum() == 18:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-#            elif self.sum() == 17 and (self.skill+self.mod < 16):
-#                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-            elif self.sum() == 17:
-                if (self.skill+self.mod) < 16:
-                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-                else:
-                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
-            elif  Diff > 9:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +" </font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
-
-        return myStr
-
-class gurpsdefaultskill(std):
-    
-    def __init__(self,source=[],stat=0,defaultlevel=0,mod=0):
-        std.__init__(self,source)
-        self.stat = stat
-        self.defaultlevel = defaultlevel
-        self.mod = mod
-
-    
-    def is_success(self):
-        if self.stat < 21:
-            intSkillVal = self.stat + self.defaultlevel + self.mod
-        else:
-            intSkillVal = 20 + self.defaultlevel + self.mod
-        return (((self.sum()) <= intSkillVal) and (self.sum() < 17))
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="]"
-        myStr += " = <b>" + str(self.sum()) + "</b>"
-        strRule = ""
-        if self.stat < 21:
-            intSkillVal = self.stat + self.defaultlevel + self.mod
-        else:
-            intSkillVal = 20 + self.defaultlevel + self.mod
-            strRule = "<br />Rule of 20 in effect [B173, B344]"
-
-        myStr += " vs <b>(" + str(intSkillVal) + ")</b>"
-
-        Diff = abs((intSkillVal) - self.sum())
-
-        if self.is_success():
-            if self.sum() == 3 or self.sum() == 4:
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
-            elif self.sum() == 5 and (intSkillVal > 14):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +"</font> [B556]"
-            elif self.sum() == 6 and (intSkillVal > 15):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +"</font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +"</font>"
-        else:
-            if self.sum() == 18:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-            elif self.sum() == 17:
-                if intSkillVal < 16:
-                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-                else:
-                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
-            elif  Diff > 9:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +"</font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +"</font>"
-
-        myStr += strRule
-        return myStr
-
-class gurpssupernatural(std):
-    
-    def __init__(self,source=[],skill=0,resistance=0,mod=0):
-        std.__init__(self,source)
-        self.skill = skill
-        self.resistance = resistance
-        self.mod = mod
-
-    
-    def is_success(self):
-        if self.skill+self.mod > 16:
-            if self.resistance > 16:
-                if self.resistance > self.skill+self.mod:
-                    newSkill = self.skill+self.mod
-                else:
-                    newSkill = self.resistance
-            else:
-                newSkill = 16
-        else:
-            newSkill = self.skill+self.mod
-        return (((self.sum()) <= newSkill) and (self.sum() < 17))
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="]"
-        myStr += " = <b>" + str(self.sum()) + "</b>"
-        strRule = ""
-        if self.skill+self.mod > 16:
-            if self.resistance > 16:
-                if self.resistance > self.skill+self.mod:
-                    newSkill = self.skill+self.mod
-                    strRule = "<br />Rule of 16:  Subject's Resistance is higher than skill, no change in skill [B349]"
-                else:
-                    newSkill = self.resistance
-                    strRule = "<br />Rule of 16:  Effective skill limited by subject's Resistance [B349]"
-            else:
-                newSkill = 16
-                strRule = "<br />Rule of 16:  Effective skill limited to 16 [B349]"
-        else:
-            newSkill = self.skill+self.mod
-        myStr += " vs <b>(" + str(newSkill) + ")</b>"
-
-        Diff = abs((newSkill) - self.sum())
-
-        if self.is_success():
-            if self.sum() == 3 or self.sum() == 4:
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
-            elif self.sum() == 5 and (newSkill > 14):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
-            elif self.sum() == 6 and (newSkill > 15):
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
-        else:
-            if self.sum() == 18:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-            elif self.sum() == 17:
-                if newSkill < 16:
-                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-                else:
-                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
-            elif  Diff > 9:
-                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +" </font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
-
-        myStr += strRule
-        return myStr
-
-class gurpscrit_hit(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
-        if self.sum() > 8 and self.sum() < 12:
-            myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
-        elif self.sum() == 12:
-            myStr += " <font color='#ff0000'>The blow inflicts normal damage, AND victim drops anything they hold--even if no damage penetrates DR.</font> [B556]"
-        elif self.sum() == 8:
-            myStr += " <font color='#ff0000'>Damage penetrating DR does double shock (-8 max) AND if it hits the victim's limb, it's crippled for 16-HT seconds (unless wound is enough to cripple permanently!).</font> [B556]"
-        elif self.sum() == 13 or self.sum() == 14 or self.sum() == 7:
-            myStr += " <font color='#ff0000'>If any damage penetrates DR, treat as major wound. See [B420] for major wounds.</font> [B556]"
-        elif self.sum() == 6 or self.sum() == 15:
-            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage.</font> [B556]"
-        elif self.sum() == 5 or self.sum() == 16:
-            myStr += " <font color='#ff0000'>The blow inflicts double damage.</font> [B556]"
-        elif self.sum() == 4 or self.sum() == 17:
-            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded down, after applying any armor divisors.</font> [B556]"
-        elif self.sum() == 3 or self.sum() == 18 :
-            myStr += " <font color='#ff0000'>The blow inflicts triple damage.</font> [B556]"
-
-        return myStr
-
-class gurpscrit_headblow(std):
-    
    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
-        if self.sum() > 8 and self.sum() < 12:
-            myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
-        elif self.sum() == 12 or self.sum() == 13:
-            myStr += " <font color='#ff0000'>Normal damage to the head, BUT if any penetrates DR victim is scarred (-1 to appearance, -2 if burning or corrosive attacks) OR, if <i>crushing</i> then victim deafened [see B422 for duration].</font> [B556]"
-        elif self.sum() == 8:
-            myStr += " <font color='#ff0000'>Normal damage to head, but victim knocked off balance: must Do Nothing until next turn (but can defend).</font> [B556]"
-        elif self.sum() == 14:
-            myStr += " <font color='#ff0000'>Normal damage to head, but victim drops their weapon.  If holding two weapons, roll randomly for which one is dropped.</font> [B556]"
-        elif self.sum() == 6 or self.sum() == 7:
-            myStr += " <font color='#ff0000'>If you aimed for face or skull, you hit an eye [B399];  otherwise, DR only half effective & if even 1 point damage penetrates it's a major wound [B420].  If you hit an eye and that should be impossible, treat as if a <b>4</b> were rolled, see [B556].</font> [B556]"
-        elif self.sum() == 15:
-            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage.</font> [B556]"
-        elif self.sum() == 16:
-            myStr += " <font color='#ff0000'>The blow inflicts double damage.</font> [B556]"
-        elif self.sum() == 4 or self.sum() == 5:
-            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded up, after applying armor divisors AND if even 1 point penetrates it's a major wound [B420].</font> [B556]"
-        elif self.sum() == 17:
-            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded up, after applying any armor divisors.</font> [B556]"
-        elif self.sum() == 3:
-            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage AND ignores all DR.</font> [B556]"
-        elif self.sum() == 18:
-            myStr += " <font color='#ff0000'>The blow inflicts triple damage.</font> [B556]"
-
-        return myStr
-
-class gurpscrit_miss(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
-        if self.sum() > 8 and self.sum() < 12:
-            myStr += " <font color='#ff0000'>You drop your weapon (& a <i>cheap</i> weapon breaks).</font> [B556]"
-        elif self.sum() == 12 or self.sum() == 8:
-            myStr += " <font color='#ff0000'>Your weapon turns in your hand;  must Ready it before it can be used again.</font> [B556]"
-        elif self.sum() == 13 or self.sum() == 7:
-            myStr += " <font color='#ff0000'>You lose your balance & can do nothing else (not even free actions) until next turn;  all defenses -2 until next turn.</font> [B556]"
-        elif self.sum() == 14:
-            yrdStr = str(int(random.uniform(1,7)))
-            myStr += " <font color='#ff0000'>A <i>swung</i> weapon flies from hand " + yrdStr + " yards (50% chance straight forward/backward) anyone on the target of the flying weapon makes a DX roll or takes half-damage; a <i>thrust</i> or <i>ranged</i> weapon is dropped (& a <i>cheap</i> weapon breaks).</font> [B556]"
-        elif self.sum() == 6:
-            myStr += " <font color='#ff0000'>You hit yourself in arm or leg (50/50 chance), doing half damage;  if impaling, piercing, or ranged attack, then roll again (if you hit yourself again then use that result).</font> [B556]"
-        elif self.sum() == 15:
-            myStr += " <font color='#ff0000'>You strain your shoulder!  Weapon arm crippled for 30 min;  do not drop weapon, but that arm is useless.</font> [B557]"
-        elif self.sum() == 16:
-            myStr += " <font color='#ff0000'>If <i>melee attack,</i>  you fall down!  If <i>ranged attack,</i> you lose your balance & can do nothing until next turn & all defenses -2 until next turn.</font> [B557]"
-        elif self.sum() == 5:
-            myStr += " <font color='#ff0000'>You hit yourself in the arm or leg (50/50 chance), doing normal damage;  if impaling, piercing, or ranged attack, then roll again (if you hit yourself again then use that result).</font> [B556]"
-        elif self.sum() == 4 or self.sum() == 3 or self.sum() == 17 or self.sum() == 18:
-            broke = int(random.uniform(3,19))
-            if broke >=5 and broke <=16:
-                brokestr = "it is dropped."
-            else:
-                brokestr = "the weapon also breaks!"
-            myStr += " <font color='#ff0000'>A normal weapon breaks [B485];  if solid crushing weapon OR fine, very fine, or magical weapon " + brokestr + "</font> [B556] Note, second for roll non-normal weapons already fingured into this result."
-
-        return myStr
-
-class gurpscrit_unarm(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
-        if self.sum() > 8 and self.sum() < 12:
-            myStr += " <font color='#ff0000'>You lose your balance;  you can do nothing else (not even free actions) until next turn, and all defenses -2 until next turn.</font> [B557]"
-        elif self.sum() == 12:
-            myStr += " <font color='#ff0000'>You trip; make a DX roll to avoid falling at -4 if kicking or twice the normal penatly for a technique that normally requires a DX to avoid injury on even a normal failure (e.g., Jump Kick).</font> [B557]"
-        elif self.sum() == 8:
-            myStr += " <font color='#ff0000'>You fall down!</font> [B557]"
-        elif self.sum() == 13:
-            myStr += " <font color='#ff0000'>You drop your guard:  all defenses -2 for the next turn & any Evaluate bonus or Feint penalties against you are doubled.  This is obvious to those around you.</font> [B557]"
-        elif self.sum() == 7 or self.sum() == 14:
-            myStr += " <font color='#ff0000'>You stumble:  <i>If attacking,</i> you advance one yard past opponent with them behind you (you are facing away); <i>if parrying</i> you fall down!</font> [B557]"
-        elif self.sum() == 15:
-            mslStr = str(int(random.uniform(1,4)))
-            myStr += " <font color='#ff0000'>You tear a muscle; " + mslStr + " HT damage to the limb used to attack (to one limb if two used to attack), & -3 to use it (-1 w/high pain thresh); also all atacks & defenses -1 until next turn.  If neck was injured -3 (-1 w/high pain thresh) applies to ALL actions.</font> [B557]"
-        elif self.sum() == 6:
-            myStr += " <font color='#ff0000'>You hit a solid object (wall, floor, etc.) & take crushing damage equalt to 1/2 of (your thrusting damage - your DR) (<i>EXCEPTION:</i> If attacking with natural weapons, such as claws or teeth, they <i>break</i> -1 damage on future attacks until you heal (for recovery, B422).</font> [B557]"
-        elif self.sum() == 5 or self.sum() == 16:
-            myStr += " <font color='#ff0000'>You hit a solid object (wall, floor, etc.) & take crushing damage = your thrusting damage - your DR (<i>EXCEPTION:</i> if opponent using impaling weapon, you fall on it & take damage based on your ST).  If attacking an opponent who is using an impaling weapon, you fall on <i>his weapon</i>.  You suffer the weapon's normal damage based on <i>your</i> <b>ST</b>.</font> [B557]"
-        elif self.sum() == 4:
-            myStr += " <font color='#ff0000'>If attacking or parrying with a limb, you strain the limb:  1 HP damage & it's crippled for 30 min. If biting, butting, etc., have moderate neck pain (B428) for next 20-HT min minimum of 1 minute.</font> [B557]"
-        elif self.sum() == 17:
-            myStr += " <font color='#ff0000'>If attacking or parrying with a limb, you strain the limb:  1 HP damage & it's crippled for 30 min. If IQ 3-5 animal, it loses its nerve & flees on next turn or surrenders if cornered.</font> [B557]"
-        elif self.sum() == 3 or self.sum() == 18 :
-            myStr += " <font color='#ff0000'>You knock yourself out!  Roll vs. HT every 30 min. to recover.</font> [B557]"
-
-        return myStr
-
-class gurpsspellfail(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="]"
-        myStr += " = <b>" + str(self.sum()) + "</b>"
-
-        if self.sum() == 10 or self.sum() == 11:
-            myStr += " <font color='#ff0000'>Spell produces nothing but a loud noise, bright flash, awful odor, etc.</font> [B236]"
-        elif self.sum() == 9:
-            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster is stunned (IQ roll to recover).</font> [B236]"
-        elif self.sum() == 12:
-            myStr += " <font color='#ff0000'>Spell produces a weak and useless shadow of the intended effect.</font> [B236]"
-        elif self.sum() == 8:
-            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster takes 1 point of damage.</font> [B236]"
-        elif self.sum() == 13:
-            myStr += " <font color='#ff0000'>Spell produces the reverse of the intended effect.</font> [B236]"
-        elif self.sum() == 7:
-            myStr += " <font color='#ff0000'>Spell affects someone or something other than the intended subject.</font> [B236]"
-        elif self.sum() == 14:
-            myStr += " <font color='#ff0000'>Spell seems to work, but it is only a useless illusion.</font> [B236]"
-        elif self.sum() == 5 or self.sum() == 6:
-            myStr += " <font color='#ff0000'>Spell is cast on one of the caster's companions (if harmful) or a random nearby foe (if beneficial).</font> [B236]"
-        elif self.sum() == 15 or self.sum() == 16:
-            myStr += " <font color='#ff0000'>Spell has the reverse of the intended, on the wrong target.  Roll randomly.</font> [B236]"
-        elif self.sum() == 4:
-            myStr += " <font color='#ff0000'>Spell is cast on caster (if harmful) or on a random nearby foe (if beneficial).</font> [B236]"
-        elif self.sum() == 17:
-            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster temporarily forgets the spell.  Make a weekly IQ roll (after a week passes) until the spell is remembered.</font> [B236]"
-        elif self.sum() == 3:
-            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster takes 1d of injury.</font> [B236]"
-        elif self.sum() == 18:
-            myStr += " <font color='#ff0000'>Spell fails entirely.  A demon or other malign entity appears and attacks the caster.  (GM may waive this if the caster and spell were both lily-white, pure good in intent.)</font> [B236]"
-
-        return myStr
-
-class gurpsfrightcheck(std):
-    
-    def __init__(self,source=[],skill=0,mod=0):
-        std.__init__(self,source)
-        self.skill = skill
-        self.mod = mod
-
-    
-    def is_success(self):
-        return (((self.sum()) <= self.skill+self.mod) and (self.sum() < 14))
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="]"
-        myStr += " = <b>" + str(self.sum()) + "</b>"
-
-        if self.skill+self.mod < 14:
-            myStr += " vs <b>(" + str(self.skill+self.mod) + ")</b>"
-            Diff = abs((self.skill+self.mod) - self.sum())
-        else:
-            myStr += " vs <b>(13)</b>"
-            Diff = abs(13 - self.sum())
-
-        if self.is_success():
-            if self.sum() == 3 or self.sum() == 4:
-                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
-            else:
-                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
-        else:
-                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
-
-        if self.skill + self.mod > 13:
-            myStr += " Rule of 14 in effect [B360]"
-
-        if not(self.is_success()):
-            intD1 = int(random.uniform(1,7))
-            intD2 = int(random.uniform(1,7))
-            intD3 = int(random.uniform(1,7))
-            intFright = intD1 + intD2 + intD3 + Diff
-            myStr += "<br />Rolling on Fright Check Table<br />[" + str(intD1) + "," + str(intD2) + "," + str(intD3) + "] ==> " + str(intFright - Diff) + " +  " + str(Diff) + " = " + str(intFright) + "<br />"
-            if intFright < 6:
-                myStr += "<font color='#ff0000'>Stunned for one second, then recover automatically.</font> [B360]"
-            elif intFright < 8:
-                myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. unmodified Will to snap out of it.</font> [B360]"
-            elif intFright < 10:
-                myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
-            elif intFright == 10:
-                strStun = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
-            elif intFright == 11:
-                strStun = str(int(random.uniform(2,13)))
-                myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
-            elif intFright == 12:
-                myStr += "<font color='#ff0000'>Lose your lunch.  Treat this as retching for (25-HT) seconds, and then roll vs. HT each second to recover [B428].</font> [B361]"
-            elif intFright == 13:
-                myStr += "<font color='#ff0000'>Acquire a new mental quirk.</font> [B361]"
-            elif intFright < 16:
-                strFP = str(int(random.uniform(1,7)))
-                strSeconds = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Lose " + strFP + " FP, and stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
-            elif intFright == 16:
-                strSeconds = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.  Acquire a new mental quirk.</font> [B361]"
-            elif intFright == 17:
-                strMinutes = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.</font> [B361]"
-            elif intFright == 18:
-                strMinutes = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.</font> [B361]"
-            elif intFright == 19:
-                strMinutes = str(int(random.uniform(2,13)))
-                myStr += "<font color='#ff0000'>Severe faint, lasting for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.  Take 1 HP of injury.</font> [B361]"
-            elif intFright == 20:
-                strMinutes = str(int(random.uniform(4,25)))
-                strFP = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Faint bordering on shock, lastering for " + strMinutes + " minutes.  Also, lose " + strFP + " FP.</font> [B361]"
-            elif intFright == 21:
-                strMinutes = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Panic.  You run around screaming, sit down and cry, or do something else equally pointless for " + strMinutes + " minutes.  Every minute after that, roll vs. unmodified Will to snap out of it.</font> [B361]"
-            elif intFright == 22:
-                myStr += "<font color='#ff0000'>Acquire a new -10-point Delusion (B130).</font> [B361]"
-            elif intFright == 23:
-                myStr += "<font color='#ff0000'>Acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
-            elif intFright == 24:
-                myStr += "<font color='#ff0000'>Major physical effect, set by the GM: hair turns white, age five years overnight, go partially deaf, etc.  (Acquire -15 points worth of physical disadvantages.  Each year of aging = -3 points.)</font> [B361]"
-            elif intFright == 25 :
-                myStr += "<font color='#ff0000'>If you already have a Phobia or other mental disadvantage that is logically related to the frightening incident, your self-control number becomes one step worse.  If not, or if your self-control number is already 6, add a new -10-point Phobia or other -10-point mental disadvantage.</font> [B361]"
-            elif intFright == 26:
-                strMinutes = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Delusion (B130).</font> [B361]"
-            elif intFright == 27:
-                strMinutes = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
-            elif intFright == 28:
-                myStr += "<font color='#ff0000'>Light coma.  You fall unconscious, rolling vs. HT every 30 minutes to recover.  For 6 hours after you come to, all skill rolls and attribute checks are at -2.</font> [B361]"
-            elif intFright == 29:
-                strHours = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.</font> [B361]"
-            elif intFright == 30:
-                strDays = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Catatonia.  Stare into space for " + strDays + " days.  Then roll vs. HT.  On a failed roll, remain catatonic for another " + strDays + " days, and so on.  If you have no medical care, lose 1 HP the first day, 2 HP the second day and so on.  If you survive and awaken, all skill rolls and attribute checks are at -2 for as many days as the catatonia lasted.</font> [B361]"
-            elif intFright == 31:
-                strMinutes = str(int(random.uniform(1,7)))
-                strFP = str(int(random.uniform(1,7)))
-                strInjury = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Seizure.  You lose control of your body and fall to the ground in a fit lasting " + strMinutes + " minutes and costing " + strFP + " FP.  Also, roll vs. HT.  On a failure, take " + strInjury + " HP of injury.  On a critical failure, you also lose 1 HT <i>permanently</i>.</font> [B361]"
-            elif intFright == 32:
-                strInjury = str(int(random.uniform(2,13)))
-                myStr += "<font color='#ff0000'>Stricken.  You fall to the ground, taking " + strInjury + " HP of injury in the form of a mild heart attack or stroke.</font> [B361]"
-            elif intFright == 33:
-                myStr += "<font color='#ff0000'>Total panic.  You are out of control; you might do anything (GM rolls 3d: the higher the roll, the more useless your reaction).  For instance, you might jump off a cliff to avoid the monster.  If you survive your first reaction, roll vs. Will to come out of the panic.  If you fail, the GM rolls again for another panic reaction, and so on!</font> [B361]"
-            elif intFright == 34:
-                myStr += "<font color='#ff0000'>Acquire a new -15-point Delusion (B130).</font> [B361]"
-            elif intFright == 35:
-                myStr += "<font color='#ff0000'>Acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
-            elif intFright == 36:
-                myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -20 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
-            elif intFright == 37:
-                myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -30 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
-            elif intFright == 39:
-                strHours = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Delusion (B130).</font> [B361]"
-            elif intFright == 39:
-                strHours = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
-            else:
-                strHours = str(int(random.uniform(1,7)))
-                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.  Also lose 1 point of IQ <i>permanently</i>.  This automatically reduces all IQ-based skill, including magic spells, by 1.</font> [B361]"
-        return myStr
-
-class gurpsfrightcheckfail(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-        self.mod = mod
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr +="] + " + str(self.mod)
-        intFright = self.sum() + self.mod
-        myStr += " = <b>" + str(intFright) + "</b> "
-
-        if intFright < 6:
-            myStr += "<font color='#ff0000'>Stunned for one second, then recover automatically.</font> [B360]"
-        elif intFright < 8:
-            myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. unmodified Will to snap out of it.</font> [B360]"
-        elif intFright < 10:
-            myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
-        elif intFright == 10:
-            strStun = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
-        elif intFright == 11:
-            strStun = str(int(random.uniform(2,13)))
-            myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
-        elif intFright == 12:
-            myStr += "<font color='#ff0000'>Lose your lunch.  Treat this as retching for (25-HT) seconds, and then roll vs. HT each second to recover [B428].</font> [B361]"
-        elif intFright == 13:
-            myStr += "<font color='#ff0000'>Acquire a new mental quirk.</font> [B361]"
-        elif intFright < 16:
-            strFP = str(int(random.uniform(1,7)))
-            strSeconds = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Lose " + strFP + " FP, and stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
-        elif intFright == 16:
-            strSeconds = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.  Acquire a new mental quirk.</font> [B361]"
-        elif intFright == 17:
-            strMinutes = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.</font> [B361]"
-        elif intFright == 18:
-            strMinutes = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.</font> [B361]"
-        elif intFright == 19:
-            strMinutes = str(int(random.uniform(2,13)))
-            myStr += "<font color='#ff0000'>Severe faint, lasting for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.  Take 1 HP of injury.</font> [B361]"
-        elif intFright == 20:
-            strMinutes = str(int(random.uniform(4,25)))
-            strFP = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Faint bordering on shock, lastering for " + strMinutes + " minutes.  Also, lose " + strFP + " FP.</font> [B361]"
-        elif intFright == 21:
-            strMinutes = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Panic.  You run around screaming, sit down and cry, or do something else equally pointless for " + strMinutes + " minutes.  Every minute after that, roll vs. unmodified Will to snap out of it.</font> [B361]"
-        elif intFright == 22:
-            myStr += "<font color='#ff0000'>Acquire a new -10-point Delusion (B130).</font> [B361]"
-        elif intFright == 23:
-            myStr += "<font color='#ff0000'>Acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
-        elif intFright == 24:
-            myStr += "<font color='#ff0000'>Major physical effect, set by the GM: hair turns white, age five years overnight, go partially deaf, etc.  (Acquire -15 points worth of physical disadvantages.  Each year of aging = -3 points.)</font> [B361]"
-        elif intFright == 25 :
-            myStr += "<font color='#ff0000'>If you already have a Phobia or other mental disadvantage that is logically related to the frightening incident, your self-control number becomes one step worse.  If not, or if your self-control number is already 6, add a new -10-point Phobia or other -10-point mental disadvantage.</font> [B361]"
-        elif intFright == 26:
-            strMinutes = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Delusion (B130).</font> [B361]"
-        elif intFright == 27:
-            strMinutes = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
-        elif intFright == 28:
-            myStr += "<font color='#ff0000'>Light coma.  You fall unconscious, rolling vs. HT every 30 minutes to recover.  For 6 hours after you come to, all skill rolls and attribute checks are at -2.</font> [B361]"
-        elif intFright == 29:
-            strHours = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.</font> [B361]"
-        elif intFright == 30:
-            strDays = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Catatonia.  Stare into space for " + strDays + " days.  Then roll vs. HT.  On a failed roll, remain catatonic for another " + strDays + " days, and so on.  If you have no medical care, lose 1 HP the first day, 2 HP the second day and so on.  If you survive and awaken, all skill rolls and attribute checks are at -2 for as many days as the catatonia lasted.</font> [B361]"
-        elif intFright == 31:
-            strMinutes = str(int(random.uniform(1,7)))
-            strFP = str(int(random.uniform(1,7)))
-            strInjury = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Seizure.  You lose control of your body and fall to the ground in a fit lasting " + strMinutes + " minutes and costing " + strFP + " FP.  Also, roll vs. HT.  On a failure, take " + strInjury + " HP of injury.  On a critical failure, you also lose 1 HT <i>permanently</i>.</font> [B361]"
-        elif intFright == 32:
-            strInjury = str(int(random.uniform(2,13)))
-            myStr += "<font color='#ff0000'>Stricken.  You fall to the ground, taking " + strInjury + " HP of injury in the form of a mild heart attack or stroke.</font> [B361]"
-        elif intFright == 33:
-            myStr += "<font color='#ff0000'>Total panic.  You are out of control; you might do anything (GM rolls 3d: the higher the roll, the more useless your reaction).  For instance, you might jump off a cliff to avoid the monster.  If you survive your first reaction, roll vs. Will to come out of the panic.  If you fail, the GM rolls again for another panic reaction, and so on!</font> [B361]"
-        elif intFright == 34:
-            myStr += "<font color='#ff0000'>Acquire a new -15-point Delusion (B130).</font> [B361]"
-        elif intFright == 35:
-            myStr += "<font color='#ff0000'>Acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
-        elif intFright == 36:
-            myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -20 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
-        elif intFright == 37:
-            myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -30 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
-        elif intFright == 39:
-            strHours = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Delusion (B130).</font> [B361]"
-        elif intFright == 39:
-            strHours = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
-        else:
-            strHours = str(int(random.uniform(1,7)))
-            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.  Also lose 1 point of IQ <i>permanently</i>.  This automatically reduces all IQ-based skill, including magic spells, by 1.</font> [B361]"
-
-        return myStr
--- a/orpg/dieroller/hackmaster.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-#!/usr/bin/env python
-# Copyright Not Yet, see how much I trust you
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: hackmaster.py
-# Author: Ric Soard
-# Maintainer:
-# Version:
-#   $Id: hackmaster.py,v 0.4 2003/08/12
-#
-# Description: special die roller for HackMaster(C)(TM) RPG
-#               has penetration damage - .damage(bonus,honor)
-#               has attack - .attack(bonus, honor)
-#               has severity .severity(honor)
-#               has help - .help()
-#
-#
-import random
-from die import *
-
-__version__ = "$Id: hackmaster.py,v 1.8 2006/11/15 12:11:22 digitalxero Exp $"
-
-#hackmaster Class basically passes into functional classes
-class hackmaster(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-    
-    def damage(self, mod, hon):
-        return HMdamage(self, mod, hon)
-
-    
-    def attack(self, mod, hon):
-        return HMattack(self, mod, hon)
-
-    
-    def help(self):
-        return HMhelp(self)
-
-    
-    def severity(self, honor):
-        return HMSeverity(self, honor)
-
-
-# HM Damage roller - rolles penetration as per the PHB - re-rolles on max die - 1, adds honor to the penetration rolls
-# and this appears to be invisible to the user ( if a 4 on a d4 is rolled a 3 will appear and be followed by another
-# die. if High honor then a 4 will appear followed by a another die.
-class HMdamage(std):
-    
-    def __init__(self,source=[], mod = 0, hon = 0):
-        std.__init__(self,source)
-        self.mod = mod
-        self.hon = hon
-        self.check_pen()
-        #here we roll the mod die
-        self.append(static_di(self.mod))
-        #here we roll the honor die
-        self.append(static_di(self.hon))
-
-    
-    def damage(mod = 0, hon = 0):
-        self.mod = mod
-        self.hon = hon
-
-# This function is called by default to display the die string to the chat window.
-# Our die string attempts to explain the results
-    
-    def __str__(self):
-        myStr = "Damage "
-        myStr += "[Damage Roll, Modifiers, Honor]: " + " [" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-
-        return myStr
-
-# This function checks to see if we need to reroll for penetration
-    
-    def check_pen(self):
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() >= self.data[i].sides:
-                self.pen_roll(i)
-
-#this function rolls the penetration die, and checks to see if it needs to be re-rolled again.
-    
-    def pen_roll(self,num):
-        result = int(random.uniform(1,self.data[num].sides+1))
-        self.data[num].value += (result - 1 + self.hon)
-        self.data[num].history.append(result - 1 + self.hon)
-        if result >= self.data[num].sides:
-            self.pen_roll(num)
-
-# this function rolls for the HM Attack. the function checks for a 20 and displays critical, and a 1
-# and displays fumble
-class HMattack(std):
-    
-    def __init__(self, source=[], mod = 0, base_severity = 0, hon = 0, size = 0):
-        std.__init__(self,source)
-        self.size = size
-        self.mod = mod
-        self.base_severity = base_severity
-        self.hon = hon
-        self.fumble = 0
-        self.crit = 0
-        self.check_crit()
-        #this is a static die that adds the modifier
-        self.append(static_di(self.mod))
-        #this is a static die that adds honor, we want high rolls so it's +1
-        self.append(static_di(self.hon))
-
-
-    
-    def check_crit(self):
-        if self.data[0] == self.data[0].sides:
-            self.crit = 1
-        if self.data[0] == 1:
-            self.fumble = 1
-
-
-    #this function is the out put to the chat window, it basicaly just displays the roll unless
-    #it's a natural 20, or a natural 1
-    
-    def __str__(self):
-        if self.crit > 0:
-            myStr = "Critical Hit!!: "
-        elif self.fumble > 0:
-            myStr = "FUMBLE!!"
-        else:
-            myStr = "To Hit:"
-        myStr += "[To Hit Roll, Modifiers, Honor]" + " [" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-        return myStr
-
-class HMhelp(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        self.source = source
-
-    
-    def __str__(self):
-        myStr = " <br /> .attack(Bonus, Honor): <br />"
-        myStr += " The attack roll rolles the dice and adds your bonus <br />"
-        myStr += " and honor modifier and returns you final roll. <br />"
-        myStr += " On a natural 20 the dieroller displays Critical Hit!! <br />"
-        myStr += " On a natural 1 the dieroller displays FUMBLE!! <br />"
-        myStr += " Example A 1st level fighter with +1 to hit and a +2 sword and High Honor <br />"
-        myStr += " would roll [1d20.attack(3,1)] <br />"
-        myStr += " .damage(Bonus, Honor): <br />"
-        myStr += " The damage roll rolls the dice and rerolls on a max roll for <br />"
-        myStr += " penetration damage, the penetration die is -1 and is rerolled on a max roll <br />"
-        myStr += " The roller returns the damage dice, monidifiers, and honor <br />"
-        myStr += " Example A magic-user uses a quaterstaff +1 with high honor, he would roll <br />"
-        myStr += " [1d6.damage(1,1)] <br />"
-        myStr += " .severity(honor): <br />"
-        myStr += " the severity is for critical hit resolution - the character rolls <br />"
-        myStr += " a d8 and adds honor bonus. the die is rerolled on natural 8 and natural 1 with a -1 modifier <br />"
-        myStr += " on an 8 the reroll is added on a 1 the reroll is subtracted <br />"
-        myStr += " Example [1d8.severity(1)] <br />"
-        myStr += " .help() : <br />"
-        myStr += " displays this message <br />"
-
-        return myStr
-
-# the severity roll is for critical resolution. The die is rerolled and added
-#on a natural 8 and rerolled and subtracted on a 1
-class HMSeverity(std):
-    
-    def __init__(self, source =[], honor=0):
-        std.__init__(self,source)
-        self.source = source
-        self.hon = honor
-        self.data = []
-        self.append(di(8))
-        self.CheckReroll()
-        self.append(static_di(self.hon))
-
-
-    
-    def __str__(self):
-        myStr = "[Severity Dice, Honor]" + " [" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-        return myStr
-
-    
-    def CheckReroll(self):
-        if self.data[0] == self.data[0].sides:
-            self.crit_chain(0,1)
-        if self.data[0] == 1:
-            self.crit_chain(0,-1)
-
-    #this function needes moved for severity
-    
-    def crit_chain(self,num,neg):
-        result = int(random.uniform(1,self.data[num].sides+1))
-        self.data[num].value += (((result - 1) * neg) + self.hon)
-        self.data[num].history.append(((result - 1) * neg) + self.hon)
-        if result >= self.data[num].sides:
-            self.crit_chain(num,1)
-        if result == 1:
-            self.crit_chain(num,-1)
--- a/orpg/dieroller/hero.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: Hero.py
-# Version:
-#   $Id: Hero.py,v .3 DJM & Heroman
-#
-# Description: Hero System die roller originally based on Posterboy's D20 Dieroller
-#
-# Changelog:
-# v.3 by Heroman
-# Added hl() to show hit location (+side), and hk() for Hit Location killing damage
-# (No random stun multiplier)
-# v.2 DJM
-# Removed useless modifiers from the Normal damage roller
-# Changed Combat Value roller and SKill roller so that positive numbers are bonuses,
-# negative numbers are penalties
-# Changed Killing damage roller to correct stun multiplier bug
-# Handled new rounding issues
-#
-# v.1 original release DJM
-
-from die import *
-from time import time, clock
-import random
-
-__version__ = "$Id: hero.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
-
-# Hero stands for "Hero system" not 20 sided die :)
-
-class hero(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-# these methods return new die objects for specific options
-
-    
-    def k(self,mod):
-        return herok(self,mod)
-
-    
-    def hl(self):
-        return herohl(self)
-
-    
-    def hk(self):
-        return herohk(self)
-
-    
-    def n(self):
-        return heron(self)
-
-    
-    def cv(self,cv,mod):
-        return herocv(self,cv,mod)
-
-    
-    def sk(self,sk,mod):
-        return herosk(self,sk,mod)
-
-class herocv(std):
-    
-    def __init__(self,source=[],cv=10,mod=0):
-        std.__init__(self,source)
-        self.cv = cv
-        self.mod = mod
-
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (" + str(self.sum()) + ")"
-
-        myStr += " with a CV of " + str(self.cv)
-        myStr += " and a modifier of " + str(self.mod)
-        cvhit = 11 + self.cv - self.sum() + self.mod
-        myStr += " hits up to <b>DCV <font color='#ff0000'>" + str(cvhit) + "</font></b>"
-        return myStr
-
-class herosk(std):
-    
-    def __init__(self,source=[],sk=11,mod=0):
-        std.__init__(self,source)
-        self.sk = sk
-        self.mod = mod
-
-    
-    def is_success(self):
-        return (((self.sum()-self.mod) <= self.sk))
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        strAdd="] - "
-        swapmod=self.mod
-        if self.mod < 0:
-            strAdd= "] + "
-            swapmod= -self.mod
-        myStr += strAdd + str(swapmod)
-        modSum = self.sum()-self.mod
-        myStr += " = (" + str(modSum) + ")"
-        myStr += " vs " + str(self.sk)
-
-        if self.is_success():
-            myStr += " or less <font color='#ff0000'>Success!"
-        else:
-            myStr += " or less <font color='#ff0000'>Failure!"
-
-        Diff = self.sk - modSum
-        myStr += " by " + str(Diff) +" </font>"
-
-        return myStr
-
-class herok(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-        self.mod = mod
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>)"
-        stunx = random.randint(1,6)-1
-        if stunx <= 1:
-            stunx = 1
-        myStr += " <b>Body</b> and a stunx of (" + str(stunx)
-        stunx = stunx + self.mod
-        myStr += " + " + str(self.mod)
-        stunsum = round(self.sum()) * stunx
-        myStr += ") for a total of (<font color='#ff0000'><b>" + str(int(stunsum)) + "</b></font>) <b>Stun</b>"
-        return myStr
-
-class herohl(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-        self.mod = mod
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        side = random.randint(1,6)
-        sidestr = "Left "
-        if side >=4:
-            sidestr = "Right "
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) "
-        location = int(round(self.sum()))
-        if location <= 5:
-            myStr += "Location: <B>Head</B>, StunX:<B>x5</B>, NStun:<B>x2</B>, Bodyx:<B>x2</B>"
-        elif location == 6:
-            myStr += "Location: <B>" + sidestr + "Hand</B>, StunX:<B>x1</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        elif location == 7:
-            myStr += "Location: <B>" + sidestr + "Arm</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        elif location == 8:
-            myStr += "Location: <B>" + sidestr + "Arm</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        elif location == 9:
-            myStr += "Location: <B>" + sidestr + "Shoulder</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
-        elif location == 10:
-            myStr += "Location: <B>Chest</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
-        elif location == 11:
-            myStr += "Location: <B>Chest</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
-        elif location == 12:
-            myStr += "Location: <B>Stomach</B>, StunX:<B>x4</B>, NStun:<B>x1 1/2</B>, Bodyx:<B>x1</B>"
-        elif location == 13:
-            myStr += "Location: <B>Vitals</B>, StunX:<B>x4</B>, NStun:<B>x1 1/2</B>, Bodyx:<B>x2</B>"
-        elif location == 14:
-            myStr += "Location: <B>" + sidestr + "Thigh</B>, StunX:<B>x2</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
-        elif location == 15:
-            myStr += "Location: <B>" + sidestr + "Leg</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        elif location == 16:
-            myStr += "Location: <B>" + sidestr + "Leg</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        elif location >= 17:
-            myStr += "Location: <B>" + sidestr + "Foot</B>, StunX:<B>x1</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
-        return myStr
-
-class herohk(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-        self.mod = mod
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>)"
-        stunx = 1
-        myStr += " <b>Body</b> "
-        stunx = stunx + self.mod
-        stunsum = round(self.sum()) * stunx
-        myStr += " for a total of (<font color='#ff0000'><b>" + str(int(stunsum)) + "</b></font>) <b>Stun</b>"
-        return myStr
-
-class heron(std):
-    
-    def __init__(self,source=[],mod=0):
-        std.__init__(self,source)
-        self.bodtot=0
-
-    
-    def __str__(self):
-        myStr = "[" + str(self.data[0])
-        if self.data[0] == 6:
-            self.bodtot=self.bodtot+2
-        else:
-            self.bodtot=self.bodtot+1
-        if self.data[0] <= 1:
-            self.bodtot=self.bodtot-1
-        for a in self.data[1:]:
-            myStr += ","
-            myStr += str(a)
-            if a == 6:
-                self.bodtot=self.bodtot+2
-            else:
-                self.bodtot=self.bodtot+1
-            if a <= 1:
-                self.bodtot=self.bodtot-1
-        myStr += "] = (<font color='#ff0000'><b>" + str(self.bodtot) + "</b></font>)"
-        myStr += " <b>Body</b> and "
-        myStr += "(<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) <b>Stun</b>"
-        return myStr
--- a/orpg/dieroller/mythos.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: wod.py
-# Author: OpenRPG Dev Team
-# Maintainer:
-# Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
-#
-# Description: WOD die roller
-#
-# Targetthr is the Threshhold target
-# for compatibility with Mage die rolls.
-# Threshhold addition by robert t childers
-from die import *
-
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
-
-
-class mythos(std):
-    
-    def __init__(self,source=[],target=0,targetthr=0):
-        std.__init__(self,source)
-        self.target = target
-        self.targetthr = targetthr
-  
-    def vs(self,target):
-        self.target = target
-        if target == 2: self.targets = [2, 4, 6, 8, 10, 12]
-        if target == 3: self.targets = [3, 6, 9, 12]
-        if target == 4: self.targets = [4, 8, 12]
-        if target == 5: self.targets = [6, 12]
-        return self
-
-    
-    def thr(self,targetthr):
-        self.targetthr = targetthr
-        return self
-
-    
-    def sum(self):
-        rolls = []
-        s = 0
-        s1 = self.targetthr
-        botch = 0
-        for a in self.data: rolls.extend(a.gethistory())
-        for r in rolls:
-            if r in self.targets or r == 12:
-                s += 1
-                if s1 >0:
-                    s1 -= 1
-                    s -= 1
-                else: botch = 1
-            elif r == 1: s -= 1
-            if botch == 1 and s < 0: s = 0
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            if self.sum() < 0: myStr += "] vs " +str(self.target)+" result of a botch"
-            elif self.sum() == 0: myStr += "] vs " +str(self.target)+" result of a failure"
-            else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
-
-
-        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/__init__.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,8 @@
+import os, os.path
+
+rollers = 'orpg.dieroller.rollers'
+rollers_path = __import__(rollers, {}, {}, ['orpg.dieroller.rollers'.split('.')[-1]]).__path__
+
+for roller in os.listdir(os.path.abspath(os.path.dirname(__file__))):
+    if roller.endswith('.py') and not roller.startswith('__'):
+        __import__("%s.%s" % (rollers, roller.split('.')[0]))
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/alternity.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,136 @@
+# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: Alternity.py
+# Version:
+#   $Id: Alternity.py,v .1 JEC (cchriss@thecastle.com)
+#
+# Description: Alternity die roller based on Posterboy's D20 Dieroller
+#
+# Changelog:
+#
+# v.1 original release JEC
+#
+# Traipse Release: 
+# The changes made in the Traipe release are intended to create a more direct connection
+# between the source and the intrepretor. IF, ELIF statements have been replaced with dictionaries,
+# unused objects have been replace with re-usable objects, and the code has been condensed.
+
+
+import re
+
+from std import std
+from time import time, clock
+from orpg.dieroller.base import di, die_base, die_rollers
+
+__version__ = "$Id: alternity.py,v 0.1 2003/01/02 12:00:00 cchriss Exp $"
+
+# Alternity stands for "Alternity system" 20 sided die plus mods
+
+class alternity(std):
+    name = "alternity" # ADDED by SEG Nov 2009 ***
+    
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+    # these methods return new die objects for specific options
+    def sk(self,score,mod):
+      return sk(self,score,mod)
+
+    def at(self,score,mod,dmgo,dmgg,dmga):
+      return at(self,score,mod,dmgo,dmgg,dmga)
+
+die_rollers.register(alternity)
+
+class sk(std):
+    def __init__(self,source=[],sc="10/5/2",mod=0):
+        std.__init__(self,source)
+        m = re.match( r"\d+", str(sc) )
+        self.score = int( m.group(0) )
+        self.mod = mod
+
+    def getMod(self,mod=0):
+        m=0
+        mods = { -4: -di(12), -3: -di(8), -2:  -di(6), -1: -di(4), 1: -di(4),
+                2: di(6), 3: di(8), 4: di(12), 5: di(20)}
+        if mod in mods.keys(): m = mods[mod].value
+        elif mod <= -5: m=-di(20).value
+        elif mod == 6:  m=di(20).value + di(20).value
+        elif mod >= 7:  m=di(20).value + di(20).value + di(20).value
+        return m
+
+    def getRolLStr(self):
+        myStr = "[" + str(self.data[0])
+        self.d20 = self.sum()
+        amod = self.getMod(self.mod)
+        self.dieRoll = self.d20 + amod
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "," + str(amod) + "] = (" + str(self.dieRoll) + ")"
+        if ( self.d20 == 1 ): self.success = 'CS'
+        if ( self.dieRoll <= self.score / 4 ): self.success = 'A'
+        elif ( self.dieRoll <= self.score / 2 ): self.success = 'G'
+        elif ( self.dieRoll <= self.score ): self.success = 'O'
+        else: self.success = 'F'
+        if ( self.d20 == 20 ): self.success = 'CF'
+        return myStr
+
+    def __str__(self):
+        myStr = self.getRolLStr()
+        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
+                    'A': " <b>AMAZING Success</b>",
+                    'G': " <b>Good Success</b>",
+                    'O': " <b>Ordinary Success</b>",
+                    'F': " <b>failure</b>"}
+        myStr += successes[self.success]
+        return myStr
+
+class at(sk):
+    ## Traipse Usage: The source I received had the damage rolls like this 1d6s, with the damage type a
+    ## letter that could be sliced from the roll. However, the roll is parsed before the letter can be
+    ## sliced from it, and with the letter attached it created an error.
+    ##
+    ## The Traipse method puts the damage type and the damage roll into a Tuple, ie (1d6, 's').
+    ## When uing this method you must include single or double quoutes around the damage type or the
+    ## software will treat it as an object.
+    def __init__(self,source=[],sc=10, mod=0, dmgo="(1d6, 's')",dmgg="(1d6, 'w')",dmga="(1d6, 'm')"):
+        sk.__init__(self,source,sc,mod)
+        self.dmgo = dmgo
+        self.dmgg = dmgg
+        self.dmga = dmga
+
+    def getdmg(self,dmgroll):
+        astr = "===> Damage "
+        droll = str(dmgroll[0])
+        dtype = dmgroll[1]
+        astr += droll
+        if dtype=="s": astr += " stun"
+        elif dtype=="w": astr += " wound"
+        elif dtype=="m":astr += " mortal"
+        return astr
+
+    def __str__(self):
+        myStr = self.getRolLStr()
+        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
+                    'A': " <b><font color='#00aa00'>AMAZING HIT</font></b> ",
+                    'G': " <b>Good HIT</b> ",
+                    'O': " <b>Ordinary HIT</b> ",
+                    'F': " <b>miss</b>"}
+        myStr += successes[self.success]
+        if self.success == 'A': myStr += self.getdmg(self.dmga)
+        elif self.success == 'G': myStr += self.getdmg(self.dmgg)
+        elif self.success == 'O': myStr += self.getdmg(self.dmgo)
+        return myStr
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/d20.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,115 @@
+# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: d20.py
+# Author: OpenRPG Dev Team
+# Maintainer:
+# Version:
+#   $Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $
+#
+# Description: d20 die roller
+__version__ = "$Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $"
+
+# d20 stands for "d20 system" not 20 sided die :)
+
+from std import std
+from orpg.dieroller.base import *
+
+class d20(std):
+    name = "d20"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+# these methods return new die objects for specific options
+
+    def attack(self,AC,mod,critical):
+        return d20attack(self,AC,mod,critical)
+
+    def dc(self,DC,mod):
+        return d20dc(self,DC,mod)
+
+die_rollers.register(d20)
+
+class d20dc(std):
+    def __init__(self,source=[],DC=10,mod=0):
+        std.__init__(self,source)
+        self.DC = DC
+        self.mod = mod
+        self.append(static_di(mod))
+
+    def is_success(self):
+        return ((self.sum() >= self.DC or self.data[0] == 20) and self.data[0] != 1)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+
+        myStr += " vs DC " + str(self.DC)
+
+        if self.is_success():
+            myStr += " Success!"
+        else:
+            myStr += " Failure!"
+
+        return myStr
+
+
+class d20attack(std):
+    def __init__(self,source=[],AC=10,mod=0,critical=20):
+        std.__init__(self,source)
+        self.mod = mod
+        self.critical = critical
+        self.AC = AC
+        self.append(static_di(mod))
+        self.critical_check()
+
+    def attack(AC=10,mod=0,critical=20):
+        self.mod = mod
+        self.critical = critical
+        self.AC = AC
+
+    def critical_check(self):
+        self.critical_result = 0
+        self.critical_roll = 0
+        if self.data[0] >= self.critical and self.is_hit():
+            self.critical_roll = die_base(20) + self.mod
+            if self.critical_roll.sum() >= self.AC:
+                self.critical_result = 1
+
+    def is_critical(self):
+        return self.critical_result
+
+    def is_hit(self):
+        return ((self.sum() >= self.AC or self.data[0] == 20) and self.data[0] != 1)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+
+        myStr += " vs AC " + str(self.AC)
+
+        if self.is_critical():
+            myStr += " Critical"
+
+        if self.is_hit():
+            myStr += " Hit!"
+        else:
+            myStr += " Miss!"
+
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/gurps.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,697 @@
+#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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
+# --
+#
+# File: gurps.py
+# Version:
+#   $Id: gurps.py,v 1.3
+#
+# Description: Modified Hero System die roller based on DJM and Heroman's Hero
+# dieroller
+#
+# GURPS is a trademark of Steve Jackson Games, and its rules and art are
+# copyrighted by Steve Jackson Games. All rights are reserved by Steve Jackson
+# Games. This game aid is the original creation of Naryt with help from Pyrandon
+# and is released for free distribution, and not for resale, under the
+# permissions granted in the Steve Jackson Games Online Policy.
+# http://www.sjgames.com/general/online_policy.html
+#
+# Errors should be reported to rpg@ormonds.net
+#
+# Changelog:
+# V 1.3  2007/03/23  Thomas M. Edwards <tmedwards@motoslave.net>
+#   Fixed gurpsskill, gurpsdefaultskill, and gurpssupernatural to correctly
+#   return a normal failure when the roll is 17 and the effective skill is 27+;
+#   previously, they would erroneously return a critical failure.  This fix also
+#   corrects the less serious issue whereby rolls of 17 and an effective skill
+#   of 17-26 would report "failure by X" instead of merely "failure", which is
+#   wrong as the only reason the roll failed was because a 17 was rolled, not
+#   because the roll exceeded the effective skill.
+# V 1.2 29 October 2006, added defaultskill (Rule of 20 [B344]), supernatural
+#   (Rule of 16 [B349]).  The frightcheck roll is now the actual Fright Check
+#   (with Rule of 14 [B360]) and a lookup oon the Fright Check Table if needed.
+#   The fightcheckfail roll is the old Fright Check Table lookup.
+#   Removes the Help roller as it was nothing but trouble, see
+#   http://openrpg.wrathof.com/repository/GURPS/GURPS_Roller_1.7.xml for help
+#   in using this roller.
+# V 1 Original gurps release 2006/05/28 00:00:00, modified crit_hit, crit_headblow, crit_miss, crit_unarm, spellfail, frightcheck and help_me
+#       Corrects numerous descriptions
+# v.1 original gurps release by Naryt 2005/10/17 16:34:00
+
+from time import time, clock
+import random
+
+from std import std
+from orpg.dieroller.base import *
+
+
+__version__ = "$Id: gurps.py,v 1.5 2007/05/06 16:42:55 digitalxero Exp $"
+
+# gurps
+
+class gurps(std):
+    name = "gurps"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+# these methods return new die objects for specific options
+
+# Original msk roll renamed to be easier to understand/remember
+    def skill(self,skill,mod):
+        return gurpsskill(self,skill,mod)
+
+    def defaultskill(self,stat,defaultlevel,mod):
+        return gurpsdefaultskill(self,stat,defaultlevel,mod)
+
+    def supernatural(self,skill,resistance,mod):
+        return gurpssupernatural(self,skill,resistance,mod)
+
+    def crit_hit(self):
+        return gurpscrit_hit(self)
+
+    def crit_headblow(self):
+        return gurpscrit_headblow(self)
+
+    def crit_miss(self):
+        return gurpscrit_miss(self)
+
+    def crit_unarm(self):
+        return gurpscrit_unarm(self)
+
+    def spellfail(self):
+        return gurpsspellfail(self)
+
+    def frightcheck(self,level,mod):
+        return gurpsfrightcheck(self,level,mod)
+
+    def frightcheckfail(self,mod):
+        return gurpsfrightcheckfail(self,mod)
+
+die_rollers.register(gurps)
+
+class gurpsskill(std):
+    def __init__(self,source=[],skill=0,mod=0):
+        std.__init__(self,source)
+        self.skill = skill
+        self.mod = mod
+
+    def is_success(self):
+        return (((self.sum()) <= self.skill+self.mod) and (self.sum() < 17))
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="]"
+        myStr += " = <b>" + str(self.sum()) + "</b>"
+        myStr += " vs <b>(" + str(self.skill+self.mod) + ")</b>"
+
+        Diff = abs((self.skill+self.mod) - self.sum())
+
+        if self.is_success():
+            if self.sum() == 3 or self.sum() == 4:
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
+            elif self.sum() == 5 and (self.skill+self.mod > 14):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
+            elif self.sum() == 6 and (self.skill+self.mod > 15):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
+        else:
+            if self.sum() == 18:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+#            elif self.sum() == 17 and (self.skill+self.mod < 16):
+#                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+            elif self.sum() == 17:
+                if (self.skill+self.mod) < 16:
+                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+                else:
+                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
+            elif  Diff > 9:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +" </font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
+
+        return myStr
+
+class gurpsdefaultskill(std):
+    def __init__(self,source=[],stat=0,defaultlevel=0,mod=0):
+        std.__init__(self,source)
+        self.stat = stat
+        self.defaultlevel = defaultlevel
+        self.mod = mod
+
+    def is_success(self):
+        if self.stat < 21:
+            intSkillVal = self.stat + self.defaultlevel + self.mod
+        else:
+            intSkillVal = 20 + self.defaultlevel + self.mod
+        return (((self.sum()) <= intSkillVal) and (self.sum() < 17))
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="]"
+        myStr += " = <b>" + str(self.sum()) + "</b>"
+        strRule = ""
+        if self.stat < 21:
+            intSkillVal = self.stat + self.defaultlevel + self.mod
+        else:
+            intSkillVal = 20 + self.defaultlevel + self.mod
+            strRule = "<br />Rule of 20 in effect [B173, B344]"
+
+        myStr += " vs <b>(" + str(intSkillVal) + ")</b>"
+
+        Diff = abs((intSkillVal) - self.sum())
+
+        if self.is_success():
+            if self.sum() == 3 or self.sum() == 4:
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
+            elif self.sum() == 5 and (intSkillVal > 14):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +"</font> [B556]"
+            elif self.sum() == 6 and (intSkillVal > 15):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +"</font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +"</font>"
+        else:
+            if self.sum() == 18:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+            elif self.sum() == 17:
+                if intSkillVal < 16:
+                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+                else:
+                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
+            elif  Diff > 9:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +"</font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +"</font>"
+
+        myStr += strRule
+        return myStr
+
+class gurpssupernatural(std):
+    def __init__(self,source=[],skill=0,resistance=0,mod=0):
+        std.__init__(self,source)
+        self.skill = skill
+        self.resistance = resistance
+        self.mod = mod
+
+    def is_success(self):
+        if self.skill+self.mod > 16:
+            if self.resistance > 16:
+                if self.resistance > self.skill+self.mod:
+                    newSkill = self.skill+self.mod
+                else:
+                    newSkill = self.resistance
+            else:
+                newSkill = 16
+        else:
+            newSkill = self.skill+self.mod
+        return (((self.sum()) <= newSkill) and (self.sum() < 17))
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="]"
+        myStr += " = <b>" + str(self.sum()) + "</b>"
+        strRule = ""
+        if self.skill+self.mod > 16:
+            if self.resistance > 16:
+                if self.resistance > self.skill+self.mod:
+                    newSkill = self.skill+self.mod
+                    strRule = "<br />Rule of 16:  Subject's Resistance is higher than skill, no change in skill [B349]"
+                else:
+                    newSkill = self.resistance
+                    strRule = "<br />Rule of 16:  Effective skill limited by subject's Resistance [B349]"
+            else:
+                newSkill = 16
+                strRule = "<br />Rule of 16:  Effective skill limited to 16 [B349]"
+        else:
+            newSkill = self.skill+self.mod
+        myStr += " vs <b>(" + str(newSkill) + ")</b>"
+
+        Diff = abs((newSkill) - self.sum())
+
+        if self.is_success():
+            if self.sum() == 3 or self.sum() == 4:
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
+            elif self.sum() == 5 and (newSkill > 14):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
+            elif self.sum() == 6 and (newSkill > 15):
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b> by " + str(Diff) +" </font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
+        else:
+            if self.sum() == 18:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+            elif self.sum() == 17:
+                if newSkill < 16:
+                    myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
+                else:
+                    myStr += " or less <font color='#ff0000'><b>Failure!</b></font> [B556]"
+            elif  Diff > 9:
+                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b> by " + str(Diff) +" </font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
+
+        myStr += strRule
+        return myStr
+
+class gurpscrit_hit(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
+        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
+            myStr += ","                  #Adds a comma after each die
+            myStr += str(a)           #Adds the value of each die.
+        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
+        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
+
+        if self.sum() > 8 and self.sum() < 12:
+            myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
+        elif self.sum() == 12:
+            myStr += " <font color='#ff0000'>The blow inflicts normal damage, AND victim drops anything they hold--even if no damage penetrates DR.</font> [B556]"
+        elif self.sum() == 8:
+            myStr += " <font color='#ff0000'>Damage penetrating DR does double shock (-8 max) AND if it hits the victim's limb, it's crippled for 16-HT seconds (unless wound is enough to cripple permanently!).</font> [B556]"
+        elif self.sum() == 13 or self.sum() == 14 or self.sum() == 7:
+            myStr += " <font color='#ff0000'>If any damage penetrates DR, treat as major wound. See [B420] for major wounds.</font> [B556]"
+        elif self.sum() == 6 or self.sum() == 15:
+            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage.</font> [B556]"
+        elif self.sum() == 5 or self.sum() == 16:
+            myStr += " <font color='#ff0000'>The blow inflicts double damage.</font> [B556]"
+        elif self.sum() == 4 or self.sum() == 17:
+            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded down, after applying any armor divisors.</font> [B556]"
+        elif self.sum() == 3 or self.sum() == 18 :
+            myStr += " <font color='#ff0000'>The blow inflicts triple damage.</font> [B556]"
+
+        return myStr
+
+class gurpscrit_headblow(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
+        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
+            myStr += ","                  #Adds a comma after each die
+            myStr += str(a)           #Adds the value of each die.
+        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
+        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
+
+        if self.sum() > 8 and self.sum() < 12:
+            myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
+        elif self.sum() == 12 or self.sum() == 13:
+            myStr += " <font color='#ff0000'>Normal damage to the head, BUT if any penetrates DR victim is scarred (-1 to appearance, -2 if burning or corrosive attacks) OR, if <i>crushing</i> then victim deafened [see B422 for duration].</font> [B556]"
+        elif self.sum() == 8:
+            myStr += " <font color='#ff0000'>Normal damage to head, but victim knocked off balance: must Do Nothing until next turn (but can defend).</font> [B556]"
+        elif self.sum() == 14:
+            myStr += " <font color='#ff0000'>Normal damage to head, but victim drops their weapon.  If holding two weapons, roll randomly for which one is dropped.</font> [B556]"
+        elif self.sum() == 6 or self.sum() == 7:
+            myStr += " <font color='#ff0000'>If you aimed for face or skull, you hit an eye [B399];  otherwise, DR only half effective & if even 1 point damage penetrates it's a major wound [B420].  If you hit an eye and that should be impossible, treat as if a <b>4</b> were rolled, see [B556].</font> [B556]"
+        elif self.sum() == 15:
+            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage.</font> [B556]"
+        elif self.sum() == 16:
+            myStr += " <font color='#ff0000'>The blow inflicts double damage.</font> [B556]"
+        elif self.sum() == 4 or self.sum() == 5:
+            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded up, after applying armor divisors AND if even 1 point penetrates it's a major wound [B420].</font> [B556]"
+        elif self.sum() == 17:
+            myStr += " <font color='#ff0000'>The victim's DR protects at half value, rounded up, after applying any armor divisors.</font> [B556]"
+        elif self.sum() == 3:
+            myStr += " <font color='#ff0000'>The blow inflicts maximum normal damage AND ignores all DR.</font> [B556]"
+        elif self.sum() == 18:
+            myStr += " <font color='#ff0000'>The blow inflicts triple damage.</font> [B556]"
+
+        return myStr
+
+class gurpscrit_miss(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
+        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
+            myStr += ","                  #Adds a comma after each die
+            myStr += str(a)           #Adds the value of each die.
+        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
+        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
+
+        if self.sum() > 8 and self.sum() < 12:
+            myStr += " <font color='#ff0000'>You drop your weapon (& a <i>cheap</i> weapon breaks).</font> [B556]"
+        elif self.sum() == 12 or self.sum() == 8:
+            myStr += " <font color='#ff0000'>Your weapon turns in your hand;  must Ready it before it can be used again.</font> [B556]"
+        elif self.sum() == 13 or self.sum() == 7:
+            myStr += " <font color='#ff0000'>You lose your balance & can do nothing else (not even free actions) until next turn;  all defenses -2 until next turn.</font> [B556]"
+        elif self.sum() == 14:
+            yrdStr = str(int(random.uniform(1,7)))
+            myStr += " <font color='#ff0000'>A <i>swung</i> weapon flies from hand " + yrdStr + " yards (50% chance straight forward/backward) anyone on the target of the flying weapon makes a DX roll or takes half-damage; a <i>thrust</i> or <i>ranged</i> weapon is dropped (& a <i>cheap</i> weapon breaks).</font> [B556]"
+        elif self.sum() == 6:
+            myStr += " <font color='#ff0000'>You hit yourself in arm or leg (50/50 chance), doing half damage;  if impaling, piercing, or ranged attack, then roll again (if you hit yourself again then use that result).</font> [B556]"
+        elif self.sum() == 15:
+            myStr += " <font color='#ff0000'>You strain your shoulder!  Weapon arm crippled for 30 min;  do not drop weapon, but that arm is useless.</font> [B557]"
+        elif self.sum() == 16:
+            myStr += " <font color='#ff0000'>If <i>melee attack,</i>  you fall down!  If <i>ranged attack,</i> you lose your balance & can do nothing until next turn & all defenses -2 until next turn.</font> [B557]"
+        elif self.sum() == 5:
+            myStr += " <font color='#ff0000'>You hit yourself in the arm or leg (50/50 chance), doing normal damage;  if impaling, piercing, or ranged attack, then roll again (if you hit yourself again then use that result).</font> [B556]"
+        elif self.sum() == 4 or self.sum() == 3 or self.sum() == 17 or self.sum() == 18:
+            broke = int(random.uniform(3,19))
+            if broke >=5 and broke <=16:
+                brokestr = "it is dropped."
+            else:
+                brokestr = "the weapon also breaks!"
+            myStr += " <font color='#ff0000'>A normal weapon breaks [B485];  if solid crushing weapon OR fine, very fine, or magical weapon " + brokestr + "</font> [B556] Note, second for roll non-normal weapons already fingured into this result."
+
+        return myStr
+
+class gurpscrit_unarm(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
+        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
+            myStr += ","                  #Adds a comma after each die
+            myStr += str(a)           #Adds the value of each die.
+        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
+        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
+
+        if self.sum() > 8 and self.sum() < 12:
+            myStr += " <font color='#ff0000'>You lose your balance;  you can do nothing else (not even free actions) until next turn, and all defenses -2 until next turn.</font> [B557]"
+        elif self.sum() == 12:
+            myStr += " <font color='#ff0000'>You trip; make a DX roll to avoid falling at -4 if kicking or twice the normal penatly for a technique that normally requires a DX to avoid injury on even a normal failure (e.g., Jump Kick).</font> [B557]"
+        elif self.sum() == 8:
+            myStr += " <font color='#ff0000'>You fall down!</font> [B557]"
+        elif self.sum() == 13:
+            myStr += " <font color='#ff0000'>You drop your guard:  all defenses -2 for the next turn & any Evaluate bonus or Feint penalties against you are doubled.  This is obvious to those around you.</font> [B557]"
+        elif self.sum() == 7 or self.sum() == 14:
+            myStr += " <font color='#ff0000'>You stumble:  <i>If attacking,</i> you advance one yard past opponent with them behind you (you are facing away); <i>if parrying</i> you fall down!</font> [B557]"
+        elif self.sum() == 15:
+            mslStr = str(int(random.uniform(1,4)))
+            myStr += " <font color='#ff0000'>You tear a muscle; " + mslStr + " HT damage to the limb used to attack (to one limb if two used to attack), & -3 to use it (-1 w/high pain thresh); also all atacks & defenses -1 until next turn.  If neck was injured -3 (-1 w/high pain thresh) applies to ALL actions.</font> [B557]"
+        elif self.sum() == 6:
+            myStr += " <font color='#ff0000'>You hit a solid object (wall, floor, etc.) & take crushing damage equalt to 1/2 of (your thrusting damage - your DR) (<i>EXCEPTION:</i> If attacking with natural weapons, such as claws or teeth, they <i>break</i> -1 damage on future attacks until you heal (for recovery, B422).</font> [B557]"
+        elif self.sum() == 5 or self.sum() == 16:
+            myStr += " <font color='#ff0000'>You hit a solid object (wall, floor, etc.) & take crushing damage = your thrusting damage - your DR (<i>EXCEPTION:</i> if opponent using impaling weapon, you fall on it & take damage based on your ST).  If attacking an opponent who is using an impaling weapon, you fall on <i>his weapon</i>.  You suffer the weapon's normal damage based on <i>your</i> <b>ST</b>.</font> [B557]"
+        elif self.sum() == 4:
+            myStr += " <font color='#ff0000'>If attacking or parrying with a limb, you strain the limb:  1 HP damage & it's crippled for 30 min. If biting, butting, etc., have moderate neck pain (B428) for next 20-HT min minimum of 1 minute.</font> [B557]"
+        elif self.sum() == 17:
+            myStr += " <font color='#ff0000'>If attacking or parrying with a limb, you strain the limb:  1 HP damage & it's crippled for 30 min. If IQ 3-5 animal, it loses its nerve & flees on next turn or surrenders if cornered.</font> [B557]"
+        elif self.sum() == 3 or self.sum() == 18 :
+            myStr += " <font color='#ff0000'>You knock yourself out!  Roll vs. HT every 30 min. to recover.</font> [B557]"
+
+        return myStr
+
+class gurpsspellfail(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="]"
+        myStr += " = <b>" + str(self.sum()) + "</b>"
+
+        if self.sum() == 10 or self.sum() == 11:
+            myStr += " <font color='#ff0000'>Spell produces nothing but a loud noise, bright flash, awful odor, etc.</font> [B236]"
+        elif self.sum() == 9:
+            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster is stunned (IQ roll to recover).</font> [B236]"
+        elif self.sum() == 12:
+            myStr += " <font color='#ff0000'>Spell produces a weak and useless shadow of the intended effect.</font> [B236]"
+        elif self.sum() == 8:
+            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster takes 1 point of damage.</font> [B236]"
+        elif self.sum() == 13:
+            myStr += " <font color='#ff0000'>Spell produces the reverse of the intended effect.</font> [B236]"
+        elif self.sum() == 7:
+            myStr += " <font color='#ff0000'>Spell affects someone or something other than the intended subject.</font> [B236]"
+        elif self.sum() == 14:
+            myStr += " <font color='#ff0000'>Spell seems to work, but it is only a useless illusion.</font> [B236]"
+        elif self.sum() == 5 or self.sum() == 6:
+            myStr += " <font color='#ff0000'>Spell is cast on one of the caster's companions (if harmful) or a random nearby foe (if beneficial).</font> [B236]"
+        elif self.sum() == 15 or self.sum() == 16:
+            myStr += " <font color='#ff0000'>Spell has the reverse of the intended, on the wrong target.  Roll randomly.</font> [B236]"
+        elif self.sum() == 4:
+            myStr += " <font color='#ff0000'>Spell is cast on caster (if harmful) or on a random nearby foe (if beneficial).</font> [B236]"
+        elif self.sum() == 17:
+            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster temporarily forgets the spell.  Make a weekly IQ roll (after a week passes) until the spell is remembered.</font> [B236]"
+        elif self.sum() == 3:
+            myStr += " <font color='#ff0000'>Spell fails entirely.  Caster takes 1d of injury.</font> [B236]"
+        elif self.sum() == 18:
+            myStr += " <font color='#ff0000'>Spell fails entirely.  A demon or other malign entity appears and attacks the caster.  (GM may waive this if the caster and spell were both lily-white, pure good in intent.)</font> [B236]"
+
+        return myStr
+
+class gurpsfrightcheck(std):
+    def __init__(self,source=[],skill=0,mod=0):
+        std.__init__(self,source)
+        self.skill = skill
+        self.mod = mod
+
+    def is_success(self):
+        return (((self.sum()) <= self.skill+self.mod) and (self.sum() < 14))
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="]"
+        myStr += " = <b>" + str(self.sum()) + "</b>"
+
+        if self.skill+self.mod < 14:
+            myStr += " vs <b>(" + str(self.skill+self.mod) + ")</b>"
+            Diff = abs((self.skill+self.mod) - self.sum())
+        else:
+            myStr += " vs <b>(13)</b>"
+            Diff = abs(13 - self.sum())
+
+        if self.is_success():
+            if self.sum() == 3 or self.sum() == 4:
+                myStr += " or less <font color='#ff0000'><b>Critical Success!</b></font> [B556]"
+            else:
+                myStr += " or less <font color='#ff0000'><b>Success!</b> by " + str(Diff) +" </font>"
+        else:
+            myStr += " or less <font color='#ff0000'><b>Failure!</b> by " + str(Diff) +" </font>"
+
+        if self.skill + self.mod > 13:
+            myStr += " Rule of 14 in effect [B360]"
+
+        if not(self.is_success()):
+            intD1 = int(random.uniform(1,7))
+            intD2 = int(random.uniform(1,7))
+            intD3 = int(random.uniform(1,7))
+            intFright = intD1 + intD2 + intD3 + Diff
+            myStr += "<br />Rolling on Fright Check Table<br />[" + str(intD1) + "," + str(intD2) + "," + str(intD3) + "] ==> " + str(intFright - Diff) + " +  " + str(Diff) + " = " + str(intFright) + "<br />"
+            if intFright < 6:
+                myStr += "<font color='#ff0000'>Stunned for one second, then recover automatically.</font> [B360]"
+            elif intFright < 8:
+                myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. unmodified Will to snap out of it.</font> [B360]"
+            elif intFright < 10:
+                myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
+            elif intFright == 10:
+                strStun = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
+            elif intFright == 11:
+                strStun = str(int(random.uniform(2,13)))
+                myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
+            elif intFright == 12:
+                myStr += "<font color='#ff0000'>Lose your lunch.  Treat this as retching for (25-HT) seconds, and then roll vs. HT each second to recover [B428].</font> [B361]"
+            elif intFright == 13:
+                myStr += "<font color='#ff0000'>Acquire a new mental quirk.</font> [B361]"
+            elif intFright < 16:
+                strFP = str(int(random.uniform(1,7)))
+                strSeconds = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Lose " + strFP + " FP, and stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
+            elif intFright == 16:
+                strSeconds = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.  Acquire a new mental quirk.</font> [B361]"
+            elif intFright == 17:
+                strMinutes = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.</font> [B361]"
+            elif intFright == 18:
+                strMinutes = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.</font> [B361]"
+            elif intFright == 19:
+                strMinutes = str(int(random.uniform(2,13)))
+                myStr += "<font color='#ff0000'>Severe faint, lasting for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.  Take 1 HP of injury.</font> [B361]"
+            elif intFright == 20:
+                strMinutes = str(int(random.uniform(4,25)))
+                strFP = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Faint bordering on shock, lastering for " + strMinutes + " minutes.  Also, lose " + strFP + " FP.</font> [B361]"
+            elif intFright == 21:
+                strMinutes = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Panic.  You run around screaming, sit down and cry, or do something else equally pointless for " + strMinutes + " minutes.  Every minute after that, roll vs. unmodified Will to snap out of it.</font> [B361]"
+            elif intFright == 22:
+                myStr += "<font color='#ff0000'>Acquire a new -10-point Delusion (B130).</font> [B361]"
+            elif intFright == 23:
+                myStr += "<font color='#ff0000'>Acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
+            elif intFright == 24:
+                myStr += "<font color='#ff0000'>Major physical effect, set by the GM: hair turns white, age five years overnight, go partially deaf, etc.  (Acquire -15 points worth of physical disadvantages.  Each year of aging = -3 points.)</font> [B361]"
+            elif intFright == 25 :
+                myStr += "<font color='#ff0000'>If you already have a Phobia or other mental disadvantage that is logically related to the frightening incident, your self-control number becomes one step worse.  If not, or if your self-control number is already 6, add a new -10-point Phobia or other -10-point mental disadvantage.</font> [B361]"
+            elif intFright == 26:
+                strMinutes = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Delusion (B130).</font> [B361]"
+            elif intFright == 27:
+                strMinutes = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
+            elif intFright == 28:
+                myStr += "<font color='#ff0000'>Light coma.  You fall unconscious, rolling vs. HT every 30 minutes to recover.  For 6 hours after you come to, all skill rolls and attribute checks are at -2.</font> [B361]"
+            elif intFright == 29:
+                strHours = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.</font> [B361]"
+            elif intFright == 30:
+                strDays = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Catatonia.  Stare into space for " + strDays + " days.  Then roll vs. HT.  On a failed roll, remain catatonic for another " + strDays + " days, and so on.  If you have no medical care, lose 1 HP the first day, 2 HP the second day and so on.  If you survive and awaken, all skill rolls and attribute checks are at -2 for as many days as the catatonia lasted.</font> [B361]"
+            elif intFright == 31:
+                strMinutes = str(int(random.uniform(1,7)))
+                strFP = str(int(random.uniform(1,7)))
+                strInjury = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Seizure.  You lose control of your body and fall to the ground in a fit lasting " + strMinutes + " minutes and costing " + strFP + " FP.  Also, roll vs. HT.  On a failure, take " + strInjury + " HP of injury.  On a critical failure, you also lose 1 HT <i>permanently</i>.</font> [B361]"
+            elif intFright == 32:
+                strInjury = str(int(random.uniform(2,13)))
+                myStr += "<font color='#ff0000'>Stricken.  You fall to the ground, taking " + strInjury + " HP of injury in the form of a mild heart attack or stroke.</font> [B361]"
+            elif intFright == 33:
+                myStr += "<font color='#ff0000'>Total panic.  You are out of control; you might do anything (GM rolls 3d: the higher the roll, the more useless your reaction).  For instance, you might jump off a cliff to avoid the monster.  If you survive your first reaction, roll vs. Will to come out of the panic.  If you fail, the GM rolls again for another panic reaction, and so on!</font> [B361]"
+            elif intFright == 34:
+                myStr += "<font color='#ff0000'>Acquire a new -15-point Delusion (B130).</font> [B361]"
+            elif intFright == 35:
+                myStr += "<font color='#ff0000'>Acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
+            elif intFright == 36:
+                myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -20 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
+            elif intFright == 37:
+                myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -30 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
+            elif intFright == 39:
+                strHours = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Delusion (B130).</font> [B361]"
+            elif intFright == 39:
+                strHours = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
+            else:
+                strHours = str(int(random.uniform(1,7)))
+                myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.  Also lose 1 point of IQ <i>permanently</i>.  This automatically reduces all IQ-based skill, including magic spells, by 1.</font> [B361]"
+        return myStr
+
+class gurpsfrightcheckfail(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+        self.mod = mod
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr +="] + " + str(self.mod)
+        intFright = self.sum() + self.mod
+        myStr += " = <b>" + str(intFright) + "</b> "
+
+        if intFright < 6:
+            myStr += "<font color='#ff0000'>Stunned for one second, then recover automatically.</font> [B360]"
+        elif intFright < 8:
+            myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. unmodified Will to snap out of it.</font> [B360]"
+        elif intFright < 10:
+            myStr += "<font color='#ff0000'>Stunned for one second.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
+        elif intFright == 10:
+            strStun = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B360]"
+        elif intFright == 11:
+            strStun = str(int(random.uniform(2,13)))
+            myStr += "<font color='#ff0000'>Stunned for " + strStun + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
+        elif intFright == 12:
+            myStr += "<font color='#ff0000'>Lose your lunch.  Treat this as retching for (25-HT) seconds, and then roll vs. HT each second to recover [B428].</font> [B361]"
+        elif intFright == 13:
+            myStr += "<font color='#ff0000'>Acquire a new mental quirk.</font> [B361]"
+        elif intFright < 16:
+            strFP = str(int(random.uniform(1,7)))
+            strSeconds = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Lose " + strFP + " FP, and stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.</font> [B361]"
+        elif intFright == 16:
+            strSeconds = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Stunned for " + strSeconds + " seconds.  Every second after that, roll vs. Will, plus whatever bonuses or penalties you had on your original roll, to snap out of it.  Acquire a new mental quirk.</font> [B361]"
+        elif intFright == 17:
+            strMinutes = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.</font> [B361]"
+        elif intFright == 18:
+            strMinutes = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.</font> [B361]"
+        elif intFright == 19:
+            strMinutes = str(int(random.uniform(2,13)))
+            myStr += "<font color='#ff0000'>Severe faint, lasting for " + strMinutes + " minutes.  Every minute after that roll vs. HT to recover.  Take 1 HP of injury.</font> [B361]"
+        elif intFright == 20:
+            strMinutes = str(int(random.uniform(4,25)))
+            strFP = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Faint bordering on shock, lastering for " + strMinutes + " minutes.  Also, lose " + strFP + " FP.</font> [B361]"
+        elif intFright == 21:
+            strMinutes = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Panic.  You run around screaming, sit down and cry, or do something else equally pointless for " + strMinutes + " minutes.  Every minute after that, roll vs. unmodified Will to snap out of it.</font> [B361]"
+        elif intFright == 22:
+            myStr += "<font color='#ff0000'>Acquire a new -10-point Delusion (B130).</font> [B361]"
+        elif intFright == 23:
+            myStr += "<font color='#ff0000'>Acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
+        elif intFright == 24:
+            myStr += "<font color='#ff0000'>Major physical effect, set by the GM: hair turns white, age five years overnight, go partially deaf, etc.  (Acquire -15 points worth of physical disadvantages.  Each year of aging = -3 points.)</font> [B361]"
+        elif intFright == 25 :
+            myStr += "<font color='#ff0000'>If you already have a Phobia or other mental disadvantage that is logically related to the frightening incident, your self-control number becomes one step worse.  If not, or if your self-control number is already 6, add a new -10-point Phobia or other -10-point mental disadvantage.</font> [B361]"
+        elif intFright == 26:
+            strMinutes = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Delusion (B130).</font> [B361]"
+        elif intFright == 27:
+            strMinutes = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Faint for " + strMinutes + " minutes and roll vs. HT immediately.  On a failed roll, take 1 HP of injury as you collapse.  Every minute after that roll vs. HT to recover.  Also acquire a new -10-point Phobia (B148) or other -10-point mental disadvantage.</font> [B361]"
+        elif intFright == 28:
+            myStr += "<font color='#ff0000'>Light coma.  You fall unconscious, rolling vs. HT every 30 minutes to recover.  For 6 hours after you come to, all skill rolls and attribute checks are at -2.</font> [B361]"
+        elif intFright == 29:
+            strHours = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.</font> [B361]"
+        elif intFright == 30:
+            strDays = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Catatonia.  Stare into space for " + strDays + " days.  Then roll vs. HT.  On a failed roll, remain catatonic for another " + strDays + " days, and so on.  If you have no medical care, lose 1 HP the first day, 2 HP the second day and so on.  If you survive and awaken, all skill rolls and attribute checks are at -2 for as many days as the catatonia lasted.</font> [B361]"
+        elif intFright == 31:
+            strMinutes = str(int(random.uniform(1,7)))
+            strFP = str(int(random.uniform(1,7)))
+            strInjury = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Seizure.  You lose control of your body and fall to the ground in a fit lasting " + strMinutes + " minutes and costing " + strFP + " FP.  Also, roll vs. HT.  On a failure, take " + strInjury + " HP of injury.  On a critical failure, you also lose 1 HT <i>permanently</i>.</font> [B361]"
+        elif intFright == 32:
+            strInjury = str(int(random.uniform(2,13)))
+            myStr += "<font color='#ff0000'>Stricken.  You fall to the ground, taking " + strInjury + " HP of injury in the form of a mild heart attack or stroke.</font> [B361]"
+        elif intFright == 33:
+            myStr += "<font color='#ff0000'>Total panic.  You are out of control; you might do anything (GM rolls 3d: the higher the roll, the more useless your reaction).  For instance, you might jump off a cliff to avoid the monster.  If you survive your first reaction, roll vs. Will to come out of the panic.  If you fail, the GM rolls again for another panic reaction, and so on!</font> [B361]"
+        elif intFright == 34:
+            myStr += "<font color='#ff0000'>Acquire a new -15-point Delusion (B130).</font> [B361]"
+        elif intFright == 35:
+            myStr += "<font color='#ff0000'>Acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
+        elif intFright == 36:
+            myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -20 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
+        elif intFright == 37:
+            myStr += "<font color='#ff0000'>Severe physical effect, set by the GM.  (Acquire -30 points worth of physical disadvantages, aging = -3 per year).</font> [B361]"
+        elif intFright == 39:
+            strHours = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Delusion (B130).</font> [B361]"
+        elif intFright == 39:
+            strHours = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.</font> [B361]"
+        else:
+            strHours = str(int(random.uniform(1,7)))
+            myStr += "<font color='#ff0000'>Coma.  You fall unconcious for " + strHours + " hours.  At the end of the " + strHours + " hours, roll vs. HT to recover.  Continue to roll every " + strHours + " hours until you recover.  Also acquire a new -15-point Phobia (B148) or other -15-point mental disadvantage.  Also lose 1 point of IQ <i>permanently</i>.  This automatically reduces all IQ-based skill, including magic spells, by 1.</font> [B361]"
+
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/hackmaster.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+# Copyright Not Yet, see how much I trust you
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: hackmaster.py
+# Author: Ric Soard
+# Maintainer:
+# Version:
+#   $Id: hackmaster.py,v 0.4 2003/08/12
+#
+# Description: special die roller for HackMaster(C)(TM) RPG
+#               has penetration damage - .damage(bonus,honor)
+#               has attack - .attack(bonus, honor)
+#               has severity .severity(honor)
+#               has help - .help()
+#
+#
+
+__version__ = "$Id: hackmaster.py,v 1.8 2006/11/15 12:11:22 digitalxero Exp $"
+
+import random
+from std import std
+from orpg.dieroller.base import *
+
+#hackmaster Class basically passes into functional classes
+class hackmaster(std):
+    name = "hackmaster"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+    def damage(self, mod, hon):
+        return HMdamage(self, mod, hon)
+
+    def attack(self, mod, hon):
+        return HMattack(self, mod, hon)
+
+    def help(self):
+        return HMhelp(self)
+
+    def severity(self, honor):
+        return HMSeverity(self, honor)
+
+die_rollers.register(hackmaster)
+
+# HM Damage roller - rolles penetration as per the PHB - re-rolles on max die - 1, adds honor to the penetration rolls
+# and this appears to be invisible to the user ( if a 4 on a d4 is rolled a 3 will appear and be followed by another
+# die. if High honor then a 4 will appear followed by a another die.
+class HMdamage(std):
+    def __init__(self,source=[], mod = 0, hon = 0):
+        std.__init__(self,source)
+        self.mod = mod
+        self.hon = hon
+        self.check_pen()
+        #here we roll the mod die
+        self.append(static_di(self.mod))
+        #here we roll the honor die
+        self.append(static_di(self.hon))
+
+    def damage(mod = 0, hon = 0):
+        self.mod = mod
+        self.hon = hon
+
+# This function is called by default to display the die string to the chat window.
+# Our die string attempts to explain the results
+    def __str__(self):
+        myStr = "Damage "
+        myStr += "[Damage Roll, Modifiers, Honor]: " + " [" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+
+        return myStr
+
+# This function checks to see if we need to reroll for penetration
+    def check_pen(self):
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() >= self.data[i].sides:
+                self.pen_roll(i)
+
+#this function rolls the penetration die, and checks to see if it needs to be re-rolled again.
+    def pen_roll(self,num):
+        result = int(random.uniform(1,self.data[num].sides+1))
+        self.data[num].value += (result - 1 + self.hon)
+        self.data[num].history.append(result - 1 + self.hon)
+        if result >= self.data[num].sides:
+            self.pen_roll(num)
+
+# this function rolls for the HM Attack. the function checks for a 20 and displays critical, and a 1
+# and displays fumble
+class HMattack(std):
+    def __init__(self, source=[], mod = 0, base_severity = 0, hon = 0, size = 0):
+        std.__init__(self,source)
+        self.size = size
+        self.mod = mod
+        self.base_severity = base_severity
+        self.hon = hon
+        self.fumble = 0
+        self.crit = 0
+        self.check_crit()
+        #this is a static die that adds the modifier
+        self.append(static_di(self.mod))
+        #this is a static die that adds honor, we want high rolls so it's +1
+        self.append(static_di(self.hon))
+
+
+    def check_crit(self):
+        if self.data[0] == self.data[0].sides:
+            self.crit = 1
+        if self.data[0] == 1:
+            self.fumble = 1
+
+
+    #this function is the out put to the chat window, it basicaly just displays the roll unless
+    #it's a natural 20, or a natural 1
+    def __str__(self):
+        if self.crit > 0:
+            myStr = "Critical Hit!!: "
+        elif self.fumble > 0:
+            myStr = "FUMBLE!!"
+        else:
+            myStr = "To Hit:"
+        myStr += "[To Hit Roll, Modifiers, Honor]" + " [" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+        return myStr
+
+class HMhelp(std):
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        self.source = source
+
+    def __str__(self):
+        myStr = " <br /> .attack(Bonus, Honor): <br />"
+        myStr += " The attack roll rolles the dice and adds your bonus <br />"
+        myStr += " and honor modifier and returns you final roll. <br />"
+        myStr += " On a natural 20 the dieroller displays Critical Hit!! <br />"
+        myStr += " On a natural 1 the dieroller displays FUMBLE!! <br />"
+        myStr += " Example A 1st level fighter with +1 to hit and a +2 sword and High Honor <br />"
+        myStr += " would roll [1d20.attack(3,1)] <br />"
+        myStr += " .damage(Bonus, Honor): <br />"
+        myStr += " The damage roll rolls the dice and rerolls on a max roll for <br />"
+        myStr += " penetration damage, the penetration die is -1 and is rerolled on a max roll <br />"
+        myStr += " The roller returns the damage dice, monidifiers, and honor <br />"
+        myStr += " Example A magic-user uses a quaterstaff +1 with high honor, he would roll <br />"
+        myStr += " [1d6.damage(1,1)] <br />"
+        myStr += " .severity(honor): <br />"
+        myStr += " the severity is for critical hit resolution - the character rolls <br />"
+        myStr += " a d8 and adds honor bonus. the die is rerolled on natural 8 and natural 1 with a -1 modifier <br />"
+        myStr += " on an 8 the reroll is added on a 1 the reroll is subtracted <br />"
+        myStr += " Example [1d8.severity(1)] <br />"
+        myStr += " .help() : <br />"
+        myStr += " displays this message <br />"
+
+        return myStr
+
+# the severity roll is for critical resolution. The die is rerolled and added
+#on a natural 8 and rerolled and subtracted on a 1
+class HMSeverity(std):
+    def __init__(self, source =[], honor=0):
+        std.__init__(self,source)
+        self.source = source
+        self.hon = honor
+        self.data = []
+        self.append(di(8))
+        self.CheckReroll()
+        self.append(static_di(self.hon))
+
+
+    def __str__(self):
+        myStr = "[Severity Dice, Honor]" + " [" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+        return myStr
+
+    def CheckReroll(self):
+        if self.data[0] == self.data[0].sides:
+            self.crit_chain(0,1)
+        if self.data[0] == 1:
+            self.crit_chain(0,-1)
+
+    #this function needes moved for severity
+    def crit_chain(self,num,neg):
+        result = int(random.uniform(1,self.data[num].sides+1))
+        self.data[num].value += (((result - 1) * neg) + self.hon)
+        self.data[num].history.append(((result - 1) * neg) + self.hon)
+        if result >= self.data[num].sides:
+            self.crit_chain(num,1)
+        if result == 1:
+            self.crit_chain(num,-1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/hero.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,232 @@
+# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: Hero.py
+# Version:
+#   $Id: Hero.py,v .3 DJM & Heroman
+#
+# Description: Hero System die roller originally based on Posterboy's D20 Dieroller
+#
+# Changelog:
+# v.3 by Heroman
+# Added hl() to show hit location (+side), and hk() for Hit Location killing damage
+# (No random stun multiplier)
+# v.2 DJM
+# Removed useless modifiers from the Normal damage roller
+# Changed Combat Value roller and SKill roller so that positive numbers are bonuses,
+# negative numbers are penalties
+# Changed Killing damage roller to correct stun multiplier bug
+# Handled new rounding issues
+#
+# v.1 original release DJM
+
+__version__ = "$Id: hero.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
+
+from time import time, clock
+import random
+
+from std import std
+from orpg.dieroller.base import *
+
+# Hero stands for "Hero system" not 20 sided die :)
+
+class hero(std):
+    name = "hero"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+# these methods return new die objects for specific options
+
+    def k(self,mod):
+        return herok(self,mod)
+
+    def hl(self):
+        return herohl(self)
+
+    def hk(self):
+        return herohk(self)
+
+    def n(self):
+        return heron(self)
+
+    def cv(self,cv,mod):
+        return herocv(self,cv,mod)
+
+    def sk(self,sk,mod):
+        return herosk(self,sk,mod)
+
+die_rollers.register(hero)
+
+class herocv(std):
+    def __init__(self,source=[],cv=10,mod=0):
+        std.__init__(self,source)
+        self.cv = cv
+        self.mod = mod
+
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (" + str(self.sum()) + ")"
+
+        myStr += " with a CV of " + str(self.cv)
+        myStr += " and a modifier of " + str(self.mod)
+        cvhit = 11 + self.cv - self.sum() + self.mod
+        myStr += " hits up to <b>DCV <font color='#ff0000'>" + str(cvhit) + "</font></b>"
+        return myStr
+
+class herosk(std):
+    def __init__(self,source=[],sk=11,mod=0):
+        std.__init__(self,source)
+        self.sk = sk
+        self.mod = mod
+
+    def is_success(self):
+        return (((self.sum()-self.mod) <= self.sk))
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        strAdd="] - "
+        swapmod=self.mod
+        if self.mod < 0:
+            strAdd= "] + "
+            swapmod= -self.mod
+        myStr += strAdd + str(swapmod)
+        modSum = self.sum()-self.mod
+        myStr += " = (" + str(modSum) + ")"
+        myStr += " vs " + str(self.sk)
+
+        if self.is_success():
+            myStr += " or less <font color='#ff0000'>Success!"
+        else:
+            myStr += " or less <font color='#ff0000'>Failure!"
+
+        Diff = self.sk - modSum
+        myStr += " by " + str(Diff) +" </font>"
+
+        return myStr
+
+class herok(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+        self.mod = mod
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>)"
+        stunx = random.randint(1,6)-1
+        if stunx <= 1:
+            stunx = 1
+        myStr += " <b>Body</b> and a stunx of (" + str(stunx)
+        stunx = stunx + self.mod
+        myStr += " + " + str(self.mod)
+        stunsum = round(self.sum()) * stunx
+        myStr += ") for a total of (<font color='#ff0000'><b>" + str(int(stunsum)) + "</b></font>) <b>Stun</b>"
+        return myStr
+
+class herohl(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+        self.mod = mod
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        side = random.randint(1,6)
+        sidestr = "Left "
+        if side >=4:
+            sidestr = "Right "
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) "
+        location = int(round(self.sum()))
+        if location <= 5:
+            myStr += "Location: <B>Head</B>, StunX:<B>x5</B>, NStun:<B>x2</B>, Bodyx:<B>x2</B>"
+        elif location == 6:
+            myStr += "Location: <B>" + sidestr + "Hand</B>, StunX:<B>x1</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        elif location == 7:
+            myStr += "Location: <B>" + sidestr + "Arm</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        elif location == 8:
+            myStr += "Location: <B>" + sidestr + "Arm</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        elif location == 9:
+            myStr += "Location: <B>" + sidestr + "Shoulder</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
+        elif location == 10:
+            myStr += "Location: <B>Chest</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
+        elif location == 11:
+            myStr += "Location: <B>Chest</B>, StunX:<B>x3</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
+        elif location == 12:
+            myStr += "Location: <B>Stomach</B>, StunX:<B>x4</B>, NStun:<B>x1 1/2</B>, Bodyx:<B>x1</B>"
+        elif location == 13:
+            myStr += "Location: <B>Vitals</B>, StunX:<B>x4</B>, NStun:<B>x1 1/2</B>, Bodyx:<B>x2</B>"
+        elif location == 14:
+            myStr += "Location: <B>" + sidestr + "Thigh</B>, StunX:<B>x2</B>, NStun:<B>x1</B>, Bodyx:<B>x1</B>"
+        elif location == 15:
+            myStr += "Location: <B>" + sidestr + "Leg</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        elif location == 16:
+            myStr += "Location: <B>" + sidestr + "Leg</B>, StunX:<B>x2</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        elif location >= 17:
+            myStr += "Location: <B>" + sidestr + "Foot</B>, StunX:<B>x1</B>, NStun:<B>x1/2</B>, Bodyx:<B>x1/2</B>"
+        return myStr
+
+class herohk(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+        self.mod = mod
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = (<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>)"
+        stunx = 1
+        myStr += " <b>Body</b> "
+        stunx = stunx + self.mod
+        stunsum = round(self.sum()) * stunx
+        myStr += " for a total of (<font color='#ff0000'><b>" + str(int(stunsum)) + "</b></font>) <b>Stun</b>"
+        return myStr
+
+class heron(std):
+    def __init__(self,source=[],mod=0):
+        std.__init__(self,source)
+        self.bodtot=0
+
+    def __str__(self):
+        myStr = "[" + str(self.data[0])
+        if self.data[0] == 6:
+            self.bodtot=self.bodtot+2
+        else:
+            self.bodtot=self.bodtot+1
+        if self.data[0] <= 1:
+            self.bodtot=self.bodtot-1
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+            if a == 6:
+                self.bodtot=self.bodtot+2
+            else:
+                self.bodtot=self.bodtot+1
+            if a <= 1:
+                self.bodtot=self.bodtot-1
+        myStr += "] = (<font color='#ff0000'><b>" + str(self.bodtot) + "</b></font>)"
+        myStr += " <b>Body</b> and "
+        myStr += "(<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) <b>Stun</b>"
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/mythos.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,90 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: wod.py
+# Author: OpenRPG Dev Team
+# Maintainer:
+# Version:
+#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#
+# Description: WOD die roller
+#
+# Targetthr is the Threshhold target
+# for compatibility with Mage die rolls.
+# Threshhold addition by robert t childers
+
+from std import std
+from orpg.dieroller.base import *
+
+__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+
+
+class mythos(std):
+    name = "mythos"
+    def __init__(self,source=[],target=0,targetthr=0):
+        std.__init__(self,source)
+        self.target = target
+        self.targetthr = targetthr
+  
+    def vs(self,target):
+        self.target = target
+        if target == 2: self.targets = [2, 4, 6, 8, 10, 12]
+        if target == 3: self.targets = [3, 6, 9, 12]
+        if target == 4: self.targets = [4, 8, 12]
+        if target == 5: self.targets = [6, 12]
+        return self
+
+    
+    def thr(self,targetthr):
+        self.targetthr = targetthr
+        return self
+
+    
+    def sum(self):
+        rolls = []
+        s = 0
+        s1 = self.targetthr
+        botch = 0
+        for a in self.data: rolls.extend(a.gethistory())
+        for r in rolls:
+            if r in self.targets or r == 12:
+                s += 1
+                if s1 > 0:
+                    s1 -= 1
+                    s -= 1
+                else: botch = 1
+            elif r == 1: s -= 1
+            if botch == 1 and s < 0: s = 0
+        return s
+
+    
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            if self.sum() < 0: myStr += "] vs " +str(self.target)+" result of a botch"
+            elif self.sum() == 0: myStr += "] vs " +str(self.target)+" result of a failure"
+            else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
+        return myStr
+
+die_rollers.register(mythos)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/runequest.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,696 @@
+# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#-------------------------------------------------------------------------
+#
+#  Usage:
+#
+#   Die  Roller: /dieroller rq
+#
+#   Skill  Roll: [1d100.skill(50,0,0)]         # ( skill%, modifer, MA% )
+#
+#   Parry  Roll: [1d100.parry(50,0,0,12)]      # ( skill%, modifer, MA%, Weapon/Shield AP )
+#
+#   Dodge  Roll: [1d100.parry(50,0,0)]         # ( skill%, modifer, MA% )
+#
+#   Attack Roll: [1d100.attack(50,0,0,2,9,3,0)]
+#       ( skill%, modifer, MA%, min weap dam, max weap dam, dam bonus, truesword )
+#
+#   Sorcery Roll: [1d100.sorcery(90,   0,   3,   6,   1,   1,    1)]
+#                               (sk, mod, pow, cer, int,  acc, mlt)
+#
+#
+#
+#   Skill Training Unlimited Roll: [1d100.trainskill(30,75)]       # (starting skill%, desired skill%)
+#   Skill Training Cost Limited:   [1d100.trainskillcost(1000, 50) # (payment, starting skill%)
+#   Skill Training Time Limited:   [1d100.trainskilltime(150, 50)  # (time, strting skill%)
+#
+#-------------------------------------------------------------------------
+# --
+#
+# File: rq.py
+# Version:
+#   $Id: rq.py,v .1 pelwer
+#
+# Description: Runequest die roller originally based on Heroman's Hero Dieroller
+#
+#
+# v.1 - pelwer - 2/5/2005
+#  o Original release
+# v.2 - pelwer - 10/30/2006
+#  o Ported to openrpg+ by removing dependance on whrandom
+#  o Fixed Riposte spelling
+#  o Deleted sorcalc - never used
+#  o Added Sorcery Fumble table to sorcery spell roller
+#
+
+__version__ = "$Id: runequest.py,v 1.4 2006/11/15 12:11:22 digitalxero Exp $"
+
+from time import time, clock
+import random
+from math import floor
+
+from std import std
+from orpg.dieroller.base import *
+
+# rq stands for "Runequest"
+
+class runequest(std):
+    name = "runequest"
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+# these methods return new die objects for specific options
+
+    def skill(self,sk,mod,ma):
+        return rqskill(self,sk,mod,ma)
+
+    def parry(self,sk,mod,ma,AP):
+        return rqparry(self,sk,mod,ma,AP)
+
+    def dodge(self,sk,mod,ma):
+        return rqdodge(self,sk,mod,ma)
+
+    def attack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd):
+        return rqattack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd)
+
+    def sorcery(self,sk,mod,pow,cer,int,acc,mlt):
+        return rqsorcery(self,sk,mod,pow,cer,int,acc,mlt)
+
+    def trainskill(self,initial,final):
+        return rqtrainskill(self,initial,final)
+
+    def trainskillcost(self,cost,sk):
+        return rqtrainskillcost(self,cost,sk)
+
+    def trainskilltime(self,time,sk):
+        return rqtrainskilltime(self,time,sk)
+
+die_rollers.register(runequest)
+
+#  RQ Skill Training Cost/Time unlimited
+#
+# [1d100.trainskill(10,20)]
+#          initial skill%, final skill%
+#
+# sk    = skill %
+#
+#
+class rqtrainskill(std):
+    def __init__(self,source=[],initial=11,final=0):
+        std.__init__(self,source)
+        self.s = initial
+        self.f = final
+
+    def __str__(self):
+        myStr = "Unrestricted Training"
+
+        if self.s == 0:
+            myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
+        else:
+            cost  = 0
+            time  = 0
+            myStr = "Training: "
+
+            while self.s < self.f and self.s < 75:
+                cost   += self.s * 5
+                time   += self.s * 1
+                self.s += random.uniform(1,4) + 1
+
+            myStr  = "Training completed:\n"
+            myStr += "\tCost(" + str(int(cost)) + ")\n"
+            myStr += "\tTime(" + str(int(time)) + ")\n"
+            myStr += "\tSkill(" + str(int(self.s)) + ")"
+
+        return myStr
+
+
+#  RQ Skill Training Cost Limited
+#
+# [1d100.trainskillcost(50,0)]
+#          cost, skill%
+#
+# cost  = cash for training
+# sk    = skill %
+#
+#
+class rqtrainskillcost(std):
+    def __init__(self,source=[],cost=11,sk=0):
+        std.__init__(self,source)
+        self.cost = cost
+        self.sk   = sk
+
+    def __str__(self):
+        myStr = ""
+
+        if self.sk == 0 and self.cost >= 50:
+            myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
+        else:
+            cost  = 0
+            time  = 0
+            icost = self.sk * 5
+
+            myStr = "Training: "
+
+            while (cost + icost) < self.cost:
+                if self.sk >= 75:
+                    break
+
+                cost += icost
+                time += self.sk * 1
+                self.sk += random.uniform(1,4) + 1
+                icost = self.sk * 5
+
+            myStr  = "Training completed: "
+            myStr += "Cost(" + str(int(cost)) + ") "
+            myStr += "Time(" + str(int(time)) + ") "
+            myStr += "Skill(" + str(int(self.sk)) + ")"
+
+        return myStr
+
+
+#  RQ Skill Training Time Limited
+#
+# [1d100.trainskilltime(50,0)]
+#          time, skill%
+#
+# time  = time for training
+# sk    = skill %
+#
+#
+class rqtrainskilltime(std):
+    def __init__(self,source=[],time=11,sk=0):
+        std.__init__(self,source)
+        self.time = time
+        self.sk   = sk
+
+    def __str__(self):
+        myStr = ""
+
+        if self.sk == 0 and self.time >= 20:
+            myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
+        else:
+            cost  = 0
+            time  = 0
+            itime = self.sk * 1
+
+            myStr = "Trainingsss: "
+
+            while (time + itime) < self.time:
+                if self.sk >= 75:
+                    break
+
+                cost += self.sk * 5
+                time += itime
+                self.sk += random.uniform(1,4) + 1
+                itime = self.sk * 5
+
+            myStr  = "Training completed: "
+            myStr += "Cost(" + str(int(cost)) + ") "
+            myStr += "Time(" + str(int(time)) + ") "
+            myStr += "Skill(" + str(int(self.sk)) + ")"
+
+        return myStr
+
+#  RQ Skill Roll
+#
+# [1d100.skill(50,0,0)]
+#          skill%, modifer, ma%
+#
+# sk    = skill %
+# mod   = modifier %
+# ma    = martial arts %
+# skill = sk + mod
+#
+# success   roll <= skill
+#
+# failure   roll > skill
+#
+# crit
+#     push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( skill/20 ) );
+#
+# special
+#     push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( $skill/5 ) );
+#
+# fumble: if ( $skill > 100 ) { $fum = 0; } else { $fum = 100 - $skill; }
+#             $fum = 100 - POSIX::floor( $fum/20 );
+#             if ( $fum == 100 ) { $fum = '00'; };
+#
+class rqskill(std):
+    def __init__(self,source=[],sk=11,mod=0,ma=0):
+        std.__init__(self,source)
+        self.sk  = sk
+        self.mod = mod
+        self.ma  = ma
+
+    def is_success(self):
+        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
+
+    def is_ma(self):
+        return (self.sum() <= self.ma)
+
+    def is_special(self):
+        return (self.sum() <= int(floor((self.sk + self.mod)/5)))
+
+    def is_critical(self):
+        return (self.sum() <= int(floor((self.sk + self.mod) / 20)))
+
+    def is_fumble(self):
+        if ( self.sk >= 100 ):
+            fum = 0
+        else:
+            fum = (100 - self.sk )
+        final_fum = ( 100 - int( floor( fum/20  ) ) )
+        return (  self.sum() >= final_fum )
+
+    def __str__(self):
+        strAdd="+"
+        swapmod= self.mod
+        if self.mod < 0:
+            strAdd= "-"
+            swapmod= -self.mod
+        modSum = self.sum()
+        # build output string
+        myStr = " (" + str(modSum) + ")"
+        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
+
+        if self.is_fumble():
+            myStr += " <b><font color=red>Fumble!</font></b>"
+        elif self.is_critical():
+            myStr += " <b><font color=green>Critical!</font></b>"
+        elif self.is_special():
+            myStr += " <i><font color=green>Special!</font></i>"
+        elif self.is_success() and self.is_ma():
+            myStr += " <i><font color=green>Special!</font></i>"
+        elif self.is_success():
+            myStr += " <font color=blue>Success!</font>"
+        else:
+            myStr += " <font color=red>Failure!</font>"
+
+        Diff = self.sk - modSum
+        myStr += " </font>"
+
+        return myStr
+
+#
+# RQ Parry Roll
+#
+# same as skill but with fumble dice and armor points
+#
+# [1d100.parry(50,0,0,12)]
+#             skill%, modifer, ma%, Weapon AP
+#
+
+class rqparry(std):
+    def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
+        std.__init__(self,source)
+        self.sk = sk
+        self.mod = mod
+        self.ma  = ma
+        self.AP = AP
+
+    def is_success(self):
+        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
+
+    def is_special(self):
+        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
+
+    def is_ma(self):
+        return (self.sum() <= self.ma)
+
+    def is_riposte(self):
+        return (self.sum() <= (self.ma / 5))
+
+    def is_critical(self):
+        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
+
+    def is_fumble(self):
+        if ( self.sk >= 100 ):
+            fum = 0
+        else:
+            fum = (100 - self.sk )
+        final_fum = ( 100 - int( floor( fum/20  ) ) )
+        return (  self.sum() >= final_fum )
+
+    def __str__(self):
+
+        # get fumble roll result in case needed
+        fum_roll = random.randint(1,100)
+
+        # get special AP
+        spec_AP = int( floor ( self.AP * 1.5 ) )
+
+        # figure out +/- for modifer
+        strAdd="+"
+        swapmod= self.mod
+        if self.mod < 0:
+            strAdd= "-"
+            swapmod= -self.mod
+        modSum = self.sum()
+
+        # build output string
+        myStr = " (" + str(modSum) + ")"
+        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
+
+        if self.is_fumble():
+            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
+        elif self.is_critical() and self.is_riposte():
+            myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
+            myStr += " Riposte next SR"
+        elif self.is_critical():
+            myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
+        elif self.is_special and self.is_riposte():
+            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
+            myStr += " Riposte next SR"
+        elif self.is_special():
+            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
+        elif self.is_success() and self.is_ma():
+            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
+        elif self.is_success():
+            myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
+        else:
+            myStr += " <font color=red>Failure!</font>"
+
+        Diff = self.sk - modSum
+        myStr += " </font>"
+
+        return myStr
+
+# RQ Dodge Roll
+#
+# same as skill but with fumble dice and armor points
+#
+# [1d100.parry(50,0,0)]
+#             skill%, modifer, ma%
+#
+
+class rqdodge(std):
+    def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
+        std.__init__(self,source)
+        self.sk = sk
+        self.mod = mod
+        self.ma  = ma
+        self.AP = AP
+
+    def is_success(self):
+        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
+
+    def is_special(self):
+        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
+
+    def is_ma(self):
+        return (self.sum() <= self.ma)
+
+    def is_riposte(self):
+        return (self.sum() <= (self.ma / 5))
+
+    def is_critical(self):
+        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
+
+    def is_fumble(self):
+        if ( self.sk >= 100 ):
+            fum = 0
+        else:
+            fum = (100 - self.sk )
+        final_fum = ( 100 - int( floor( fum/20  ) ) )
+        return (  self.sum() >= final_fum )
+
+    def __str__(self):
+
+        # get fumble roll result in case needed
+        fum_roll = random.randint(1,100)
+
+        # get special AP
+        spec_AP = int( floor ( self.AP * 1.5 ) )
+
+        # figure out +/- for modifer
+        strAdd="+"
+        swapmod= self.mod
+        if self.mod < 0:
+            strAdd= "-"
+            swapmod= -self.mod
+        modSum = self.sum()
+
+        # build output string
+        myStr = " (" + str(modSum) + ")"
+        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
+
+        if self.is_fumble():
+            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
+        elif self.is_critical() and self.is_riposte():
+            myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
+            myStr += " Riposte on next SR"
+        elif self.is_critical():
+            myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
+        elif self.is_special and self.is_riposte():
+            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
+            myStr += " Riposte on next SR"
+        elif self.is_special():
+            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
+        elif self.is_success() and self.is_ma():
+            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
+        elif self.is_success():
+            myStr += " <font color=blue>Success!</font> Damage dodged</b>"
+        else:
+            myStr += " <font color=red>Failure!</font>"
+
+        Diff = self.sk - modSum
+        myStr += " </font>"
+
+        return myStr
+
+
+
+#
+# RQ Attack Roll
+#
+# same as skill but with fumble dice and armor points
+#
+# [1d100.attack(50,0,0,2,9,3,1)]
+#             skill%, modifer, ma%, min weap dam, max weap dam, dam bonus, truesword_enabled
+#
+class rqattack(std):
+    def __init__(self,source=[],sk=11,mod=0,ma=0,mindam=0,maxdam=0,bondam=0,trueswd=0):
+        std.__init__(self,source)
+        self.sk = sk
+        self.mod = mod
+        self.ma  = ma
+        self.mindam = mindam
+        self.maxdam = maxdam
+        self.bondam = bondam
+        self.trueswd = trueswd
+
+    def is_success(self):
+        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
+
+    def is_ma(self):
+        return (self.sum() <= self.ma)
+
+    def is_special(self):
+        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
+
+    def is_critical(self):
+        return ((self.sum() <= int(floor((self.sk + self.mod) / 20))))
+
+    def is_supercritical(self):
+        return (self.sum() == 1)
+
+    def is_fumble(self):
+        if ( self.sk >= 100 ):
+            fum = 0
+        else:
+            fum = (100 - self.sk )
+        final_fum = ( 100 - int( floor( fum/20  ) ) )
+        return (  self.sum() >= final_fum )
+
+    def __str__(self):
+
+        # get fumble roll result in case needed
+        fum_roll = random.randint(1,100)
+
+        # get hit location roll result in case needed
+        location = random.randint(1,20)
+        myStr = " to the ["+ str(location) + "] "
+        if location < 5:
+            myStr += "<B>Right Leg</B>"
+        elif location < 9:
+            myStr += "<B>Left Leg</B>"
+        elif location < 12:
+            myStr += "<B>Abdomen</B>"
+        elif location < 13:
+            myStr += "<B>Chest</B>"
+        elif location < 16:
+            myStr += "<B>Right Arm</B>"
+        elif location < 19:
+            myStr += "<B>Left Arm</B>"
+        else:
+            myStr += "<B>Head</B>"
+        hit_loc = myStr
+
+
+        # get normal damage in case needed
+        norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
+        norm_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
+        norm_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.bondam)
+        norm_damage_string += "}[" + str(norm_damage) + "] "
+
+        # get special/critical damage in case needed
+        crit_damage = random.randint( self.mindam*(self.trueswd+2), self.maxdam*(self.trueswd+2) ) + self.bondam
+        crit_damage_string = "{" + str( self.mindam*(self.trueswd+2) ) + "-" + str(self.maxdam*(self.trueswd+2)) + "+" + str(self.bondam) + "}[" + str(crit_damage) + "] "
+
+        # get supercritical damage in case needed
+        super_damage = norm_damage + self.maxdam
+        super_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
+        super_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.maxdam)
+        super_damage_string += "+" + str(self.bondam) + "}[" + str(super_damage) + "] "
+
+        # figure out +/- for modifer
+        strAdd="+"
+        swapmod= self.mod
+        if self.mod < 0:
+            strAdd= "-"
+            swapmod= -self.mod
+        modSum = self.sum()
+
+        # build output string
+        myStr = " (" + str(modSum) + ")"
+        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
+
+        if self.is_fumble():
+            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
+        elif (self.is_supercritical() and self.is_success()):
+            myStr += " <b><font color=green>Super Critical!</font></b> Damage: " + str(super_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
+        elif (self.is_critical() and self.is_success()):
+            myStr += " <b><font color=green>Critical!</font></b> Damage: " + str(crit_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
+        elif ( self.is_special() and self.is_success() ):
+            myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
+        elif (self.is_success() and self.is_ma()):
+            myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
+        elif self.is_success():
+            myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
+        else:
+            myStr += " <font color=red>Failure!</font>"
+
+        return myStr
+
+#
+#
+#   Sorcery Roll: [1d100.sorcery(90,   10,  5,   4,   3,   2,    1)]
+#                               (sk, mod, pow, cer, int,  acc, mlt)
+#
+# Ceremony: (+1d6% per strike rank spent on ceremony)
+# Intensity: (-3% per point of Intensity)
+# Duration: (-4% per point of Duration)
+# Range: (-5% per point of Range)
+# Multispell: (-10% per each spell over 1)
+# Acceleration: (-5% per point of Acceleration)
+# Hold: (-2% per point in spell Held)
+#
+class rqsorcery(std):
+    def __init__(self,source=[],sk=11,mod=0,pow=0,cer=0,int=0,acc=0,mlt=0):
+        std.__init__(self,source)
+        self.sk  = sk   # sorcery skill
+        self.mod = mod  # additional modifier ( from duration, range, etc )
+        self.pow = pow  # boost pow and additional pow ( from duration, range, etc )
+        self.cer = cer  # ceremony d6
+        self.int = int  # intensity ( -3% )
+        self.acc = acc  # accelerate ( -5% )
+        self.mlt = mlt  # multispell ( -10% )
+
+    def is_success(self):
+        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
+
+    def is_special(self):
+        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/5  ) ) ) )
+
+    def is_critical(self):
+        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
+
+    def is_fumble(self):
+        if ( self.sk >= 100 ):
+            fum = 0
+        else:
+            fum = (100 - self.sk )
+        final_fum = ( 100 - int( floor( fum/20  ) ) )
+        return (  self.sum() >= final_fum )
+
+    def __str__(self):
+
+        # get fumble roll result in case needed
+        fum_roll = random.randint(2,12)
+        if fum_roll == 12 :
+            fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each day to remember.</font>"
+        if fum_roll == 11 :
+            fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each hour to remember.  </font>"
+        if fum_roll == 10 :
+            fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect.  </font>"
+        if fum_roll == 9 :
+            fum_string = "<br /><font color=purple>Caster is Stunned. Roll INTx3 to recover at SR 10 each round.  </font>"
+        if fum_roll == 8 :
+            fum_string = "<br /><font color=purple>Caster takes 2D6 Damage to THP  </font>"
+        if fum_roll == 7 :
+            fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect at 2x Intensity.  </font>"
+        if fum_roll == 6 :
+            fum_string = "<br /><font color=purple>Spell is cast on companions (if harmful) or on random nearby foes (if beneficial)  </font>"
+        if fum_roll == 5 :
+            fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to Head  </font>"
+        if fum_roll == 4 :
+            fum_string = "<br /><font color=purple>Spell is cast on caster (if harmful) or on random nearby foe (if beneficial)  </font>"
+        if fum_roll == 3 :
+            fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to THP  </font>"
+        if fum_roll == 2 :
+            fum_string = "<br /><font color=purple>Caster takes 1 point of Damage to Head  </font>"
+
+            # roll ceremony
+        ceremony_roll = random.randint( self.cer, (self.cer*6) )
+
+        # subtract manipulations
+        extra_mod = self.mod
+        self.mod += ceremony_roll - self.int*3 - self.acc*5 - self.mlt*10
+
+        # add up power cost
+        extra_pow = self.pow
+        self.pow += self.int + self.mlt + self.acc
+        special_pow = int( floor( ( self.pow )/2  ) )
+
+        # figure out +/- for modifer
+        strAdd="+"
+        swapmod= self.mod
+        if self.mod < 0:
+            strAdd= "-"
+            swapmod= -self.mod
+        modSum = self.sum()
+
+        # build output string
+        myStr = " (" + str(modSum) + ")"
+        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
+
+        if self.is_fumble():
+            myStr += " <b><font color=red>Fumble!</font>  POW Cost: [" + str(self.pow) + "],</b> " + fum_string
+        elif self.is_critical():
+            myStr += " <b><font color=green>Critical!</font></b> POW Cost: [1] "
+        elif self.is_special():
+            myStr += " <i><font color=green>Special!</font></i> POW Cost: [" + str(special_pow) + "] "
+        elif self.is_success():
+            myStr += " <font color=blue>Success!</font> POW Cost: [" + str(self.pow) + "] "
+        else:
+            myStr += " <font color=red>Failure!</font> POW Cost: [1]"
+
+        # print spell details
+        myStr += "<br /> --- Other Modifiers:["    + str( extra_mod     ) + "], "
+        myStr += "Extra POW:[" + str( extra_pow     ) + "], "
+        myStr += "Ceremony:[+"          + str( ceremony_roll ) + "%], "
+        myStr += "Intensity(-3):["      + str( self.int      ) + "], "
+        myStr += "Accelerate(-5):["     + str( self.acc      ) + "], "
+        myStr += "Multispell(-10):["    + str( self.mlt      ) + "] ---"
+
+        return myStr
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/savage.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,509 @@
+# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: savage.py
+# Authors: Rich Finder
+#        : Alexandre Major
+# Maintainer:
+# Version: 0.2
+#
+# Description: Savage Worlds die roller
+# Permission was granted by Pinnacle to reprint the result descriptions from their tables on Apr 20, 2006 by Simon Lucas
+#
+
+__version__ = "$Id: savage.py,v 1.2 2007/05/06 16:42:55 digitalxero Exp $"
+
+import string
+from random import *
+
+from std import std
+from orpg.dieroller.base import *
+
+# Savage, as in Savage Worlds
+class sw(std):
+    #def __init__(self,source=[], wnd=1, loc="rnd", chmod=0):
+    def __init__(self,source=[],fmod=0):
+        std.__init__(self,source)
+
+# these methods return new die objects for specific options
+
+    def fright(self,fearmod=0):
+        return fright(self,fearmod=0)
+
+    def kob(self,wnd,loc):
+        return kob(self,wnd=1,loc="rnd")
+
+    def ooc(self):
+        return ooc(self)
+
+    def ract(self,chmod=0):
+        return ract(self,chmod=0)
+
+    def vcrit(self):
+        return vcrit(self)
+
+    def fortune(self):
+        return fortune(self)
+
+    def freak(self):
+        return freak(self)
+
+    def swdhelps(self):
+        return swdhelps(self)
+
+die_rollers.register(sw)
+
+class fright(std):
+    #-----------------The Fright Table
+    #  Rolls on the Fright - which is a 1d20 roll modified by the fear level of a monster.  This function automatically generates
+    #  The appropriate random number and then adds the fear modifier to the rol and displays the result of the roll with the effect
+    #  of that roll.
+    #  Usage:  [fright()]
+    #          [fright(6)] - if the fear modifier of the monster was 6
+    #-----------------
+    def __init__(self,fmod=0):
+        global fear
+        std.__init__(self)
+        fear=fmod
+
+    #def sum(self):
+
+    def __str__(self):
+        global fear
+        iroll = randint(1,20)
+        froll = iroll + fear
+        if froll >= 1 and froll <=4:
+            fresult = "Adrenaline Rush"
+            fdescription = "The hero's \"fight\" response takes over.  He adds +2 to all Trait and damage rolls on his next action."
+        elif froll >= 5 and froll <=8:
+            fresult = "Shaken"
+            fdescription = "The character is Shaken."
+        elif froll >=9 and froll <=12:
+            fresult = "Pankicked"
+            fdescription = "The character immediately moves his full Pace plus running die away from the danger and is Shaken."
+        elif froll >=13 and froll <=16:
+            fresult = "Minor Phobia"
+            fdescription = "The character gains a Minor Phobia Hindrance somehow associated with the trauma."
+        elif froll >=17 and froll <=18:
+            fresult = "Major Phobia"
+            fdescription = "The character gains a Major Phobia Hindrance."
+        elif froll >=19 and froll <= 20:
+            fresult = "The Mark of Fear"
+            fdescription = "The hero is Shaken and also suffers some cosmetic, physical alteration -- a white streak forms in the hero's hair, his eyes twitch constantly, or some other minor physical alteration.  This reduces his Charisma by 1."
+        else:
+            fresult = "Heart Attack"
+            fdescription = "The hero is so overwhelmed with fear that his heart stutters.  He becomes Incapacitated and must make a Vigor roll at -2.  If Successful, he's Shaken and can't attempt to recover for 1d4 rounds.  If he fails, he dies in 2d6 rounds.  A Healing roll at -4 saves the victim's life, but he remains Incapacitated."
+        myStr = "[" + str(iroll) + "+"+str(fear)+"="+str(froll)+"] ==> " + fresult +":  "+ fdescription
+        return myStr
+
+class kob(std):
+    #-------------------The Knockout Blow Table
+    #  This table used when a character has sustained more than 3 wounds.  The number wounds taken that sends a character to the
+    #  Knockout Blow Table is what gets sent with the kob command - not the total number of wounds the character currently has.
+    #  For example - a character has 2 wounds and is hit takes 2 more wounds, this will result in a total of 4 wounds, but the
+    #  number that gets sent to the kob roll is 2, because that is the number of wounds sustained that sent the character to the kob
+    #  table.
+    #
+    #  It is also important to note that if a called shot to particular area was made, that information should be sent with the "roll"
+    #  as well, because the KOB Table may need to determine some dramatic effects for permanent injuries, etc.  If a hit location was sent
+    #  the function will use that information.
+    #  Valid Hit Locations are:  h (head), g (guts), la (left arm), ra (right arm), rl (right leg), ll (left leg), c (crotch)
+    #  Usage = [kob(3)] - If 3 wounds were received that sent the player to the Knockout Blow Table - no called shot
+    #          [kob(3,"h") - If 3 wounds were received that sent the player to the Knockout Blow Table with a called shot to the head
+    #---------------------
+    global wound, loca
+    def __init__(self, wnd, loc="rnd"):
+        global wound, loca
+        std.__init__(self, wnd)
+        #Need to check to make sure that wnd is a number
+        if (int(wnd)):
+            wound = wnd
+            loca = loc
+        else:
+            mystr = "You need to supply a number for the wound."
+            return mystr
+
+    def __str__(self):
+        global wound, loca
+        itbl = "no"
+        if wound == 1:
+            wtype = "Battered and Bruised"
+            wdescription = "If your hero was previously Incapacitated, this result has no further effect. Otherwise, your hero's had the wind knocked out of him. Make a Spirit roll at the beginning of each round. If the roll is successful, he becomes Shaken and can return to the fight."
+        elif wound == 2:  #Need to roll on the Injury table as well
+            wtype = "Incapacitated"
+            wdescription = "Your hero is beaten badly enough to take him out of this fight. He's Incapacitated and must roll on the Injury Table."
+            itbl = "yes"
+        elif wound == 3:
+            wtype = "Bleeding Out"
+            wdescription = "Your hero is bleeding out and Incapacitated. Roll on the Injury Table and make a Vigor roll at the start of each combat round. A failure means the hero has lost too much blood and becomes mortally Wounded (see below; begin rolling for the Mortal Wound in the next round). With a success, he keeps bleeding and must roll again next round. With a raise, or a successful Healing roll, he stops bleeding and is Incapacitated."
+            itbl = "yes"
+        elif wound < 1:
+            wtype = "No Wounds?"
+            wdescription = "The Number of wounds specified was less than one...why are you consulting this chart?"
+        else:
+            wtype = "Mortal Wound"
+            wdescription = "Your hero has suffered a life-threatening wound and will not recover without aid. He is Incapacitated and must roll on the Injury Table. He must also make a Vigor roll at the start of each round. If the roll is failed, he passes on. A Healing roll stabilizes the victim but leaves him Incapacitated."
+            itbl = "yes"
+
+        if itbl == "yes":
+            #Determine if a Hit location was specified already
+            if loca.lower() == "h":
+                iroll = 11
+            elif loca.lower() == "g":
+                iroll = 5
+            elif loca.lower() == "ra":
+                iroll = 3
+                aroll = 2
+            elif loca.lower() == "la":
+                iroll = 3
+                aroll = 1
+            elif loca.lower() == "rl":
+                iroll = 10
+                lroll = 2
+            elif loca.lower() == "ll":
+                iroll = 10
+                lroll = 1
+            elif loca.lower() == "c":
+                iroll = 2
+            else:  #none of the above were provided...wo will need to determine randomly
+                iroll = randint(2,12)
+            #resolve the injury table stuff...
+            if iroll == 2:
+                iloc = "Unmentionables"
+                idescription = "The hero suffers an embarrassing and painful wound to the groin."
+            elif iroll == 3 or iroll == 4:
+                if loca != "ra" and loca != "la":  #  If a hit location was not specified (or not recognized) already, determine randomly
+                    aroll = randint(1,2)
+                if aroll == 1:
+                    warm = "Left"
+                else:
+                    warm = "Right"
+                iloc = warm + " Arm"
+                idescription = "The arm is rendered useless."
+            elif iroll >= 5 and iroll <= 9:  #will need to make another random roll
+                iloc = "Guts"
+                idescription = "Your hero catches one somewhere between the crotch and the chin."
+                groll = randint(1,6)
+                if groll == 1 or groll == 2:
+                    #idescription += " <b>Broken (" + str(groll) + ")</b> His Agility is reduced by a die type (min dr)."
+                    idescription += " <b>Broken (" + str(groll) + ")</b> His Agility is reduced by a die type (min d4)."
+                elif groll == 3 or groll == 4:
+                    idescription += " <b>Battered (" + str(groll) + ")</b> His Vigor is reduced by a die type (min d4)."
+                else:
+                    idescription += " <b>Busted (" + str(groll) + ")</b> His Strength is reduced by a die type (min d4)."
+            elif iroll == 10:
+                if loca != "ll" and loca != "rl":  #  If a hit location was not specified (or not recognized) already, determine randomly
+                    lroll = randint(1,2)
+                if lroll == 1:
+                    wleg = "Left"
+                else:
+                    wleg = "Right"
+                iloc = wleg + " Leg"
+                idescription = "The character's leg is crushed, broken, or mangled. His Pace is reduced by 1."
+            else:  #Will need to make another random roll for this one.
+                iloc = "Head"
+                idescription = "Your hero has suffered a grievous injury to his head."
+                hroll = randint(1,6)  #determine how the head is impacted by the wound
+                if hroll == 1 or hroll ==2:
+                    idescription += "<b>Hideous Scar (" + str(hroll) + ")</b>Your hero now has the Ugly Hindrance."
+                elif hroll == 3 or hroll == 4:
+                    idescription += "<b>Blinded (" + str(hroll) + ")</b> One or both of your hero's eyes was damaged. He gains the Bad Eyes Hindrance."
+                else:
+                    idescription += "<b>Brain Damage (" + str(hroll) + ")</b> Your hero suffers massive trauma to the head. His Smarts is reduced one die type (min d4)."
+            idescription += " Make a Vigor roll applying any wound modifiers. If the Vigor roll is failed, the injury is permanent regardless of healing. If the roll is successful, the effect goes away when all wounds are healed."
+            if iroll == 2:
+                idescription +=" If the injury is permanent, reproduction is out of the question without miracle surgery or magic."
+            if loca != "h" and loca != "g" and loca != "c" and loca != "rl" and loca != "ll" and loca != "ra" and loca != "la":
+                idescription +="<br><br><b>***If the attack that caused the Injury was directed at a specific body part, use that location instead of rolling randomly.***</b>"
+            myStr = "[" + wtype + "] ==>" + wdescription + "<br><br><b>Injury Table Result ("+ str(iroll) +"): </b> [" + iloc + "] ==> " + idescription
+        else:
+            myStr = "[" + wtype + "] ==>" + wdescription
+        return myStr
+
+class ract(std):
+    #----------------------The Reaction Table
+    #  This is used to randomly determine the general mood of NPCs toward the player characters.  This simulates a 2d6 roll
+    #  and displays the reaction.  This roll can be modified by the Charisma of the player(s).
+    #  Usage:  [ract()] - No Charisma modifier
+    #          [ract(2)] - A +2 Charisma modifier
+    #          [ract(-2)] - A -2 Charisma modifier
+    #----------------------
+    global charisma
+    def __init__(self,chmod=0):
+        global charisma
+        std.__init__(self)
+        charisma = chmod
+
+    def __str__(self):
+        global charisma
+        r1roll = randint(2,12)
+        rroll = r1roll + charisma
+        if rroll == 2:
+            reaction = "Hostile"
+            rdescription = "The NPC is openly hostile and does his best to stand in the hero's way. He won't help without an overwhelming reward or payment of some kind."
+        elif rroll >=3 and rroll <=4:
+            reaction = "Unfriendly"
+            rdescription = "The NPC is openly hostile and does his best to stand in the hero's way. He won't help without an overwhelming reward or payment of some kind."
+        elif rroll >=5 and rroll <=9:
+            reaction = "Neutral"
+            rdescription = "The NPC has no particular attitude, and will help for little reward if the task at hand is very easy. If the task is difficult, he'll require substantial payment of some kind."
+        elif rroll >=10 and rroll <=11:
+            reaction = "Friendly"
+            rdescription = "The NPC will go out of his way for the hero. He'll likely do easy tasks for free (or very little), and is willing to do more dangerous tasks for fair pay or other favors."
+        else:
+            reaction = "Helpful"
+            rdescription = "The NPC is anxious to help the hero, and will probably do so for little or no pay depending on the nature of the task."
+        #myStr = "[" + reaction + "(" + str(r1roll) + "+Charisma Mods("+str(charisma)+")="+str(rroll)+")] ==> " + rdescription
+        myStr = "["+str(r1roll)+"+"+str(charisma)+"(charisma modifier)="+str(rroll)+"] ==> "+reaction+":  "+rdescription
+        return myStr
+
+class ooc(std):
+    #--------------------The Out of Control Vehicle Table
+    #  This table is used when a vehicle is injured during combat and must determine what happens to the vehicle.  This is a 2d6
+    #  roll and displays the results of the roll.  This will also display altitude information for flying vehicles.
+    #  Usage:  [ooc()]
+    #--------------------
+    def __init__(self):
+        std.__init__(self)
+
+    def __str__(self):
+        ooroll = randint(2,12)
+        oodescripton = "Something"
+        if ooroll == 2:
+            ooeffect = "Roll Over"
+            rroll = randint(1,6)
+            oodescription = "The vehicle performs a Slip and rolls over "+ str(rroll)+ " time"
+            if rroll < 2:
+                oodescription +="s"
+            oodescription += " in that direction. Roll collision damage for the vehicle and everyone inside. Any exterior-mounted weapons or accessories are ruined."
+        elif ooroll == 3 or ooroll == 4:
+            ooeffect = "Spin"
+            sroll = randint(1,6)
+            froll = randint(1,12)
+            oodescription = "Move the vehicle "+str(sroll)+"\" in the direction of the maneuver, or "+str(sroll)+"\" away from a damaging blow. At the end of the Spin,the vehicle is facing is "+str(froll)+" o'clock."
+        elif ooroll >= 5 and ooroll <= 9:
+            ooeffect = "Skid"
+            sroll = randint(1,4)
+            oodescription = "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
+        elif ooroll == 10 or ooroll == 11:
+            ooeffect = "Slip"
+            sroll = randint(1,6)
+            oodescription = "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
+        else:
+            ooeffect = "Flip"
+            froll = randint(1,4)
+            oodescription = "The vehicle flips end over end "+str(froll)+" times. Move it forward that many increments of its own length. Roll collision damage for the vehicle, its passengers, and anything it hits. "
+            shroll = randint(1,2)
+            if shroll == 1:
+                oodescription += "<br><br><b>Note:</b> If the vehicle is slow and/or heavy (such as a tank) it Slips instead: "
+                sroll = randint(1,6)
+                oodescription += "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
+            else:
+                oodescription += "<br><br><b>Note (GM's discretion):</b> If the vehicle is slow and/or heavy (such as a tank) it Skids instead: "
+                sroll = randint(1,4)
+                oodescription += "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
+
+        oodescription += "<br><br>For flying vehicles conducting combat in the air, the vehicle"
+        altchange = randint(2,12)
+        if altchange == 2:
+            dwn = randint(2,20)
+            oodescription += " loses "+str(dwn)+"\" of altitude."
+        elif altchange == 3 or altchange == 4:
+            dwn = randint(1,10)
+            oodescription += " loses "+str(dwn)+"\" of altitude."
+        elif altchange >= 5 and altchange <= 9:
+            oodescription += " has no change in altitude."
+        else:
+            altup = randint(1,10)
+            oodescription += " gains "+str(altup)+"\" of altitude."
+        myStr = "[" + ooeffect + "(" + str(ooroll) + ")] ==> " + oodescription
+        return myStr
+
+class vcrit(std):
+    #----------------The Critical Hit Vehicle Table
+    #  This table generates a 2d6 roll to determine the Critical Hit results every time a vehicle takes a wound.  There are no
+    #  modifiers to this roll
+    #  Usage [vcrit()]
+    #----------------
+    def __init__(self):
+        std.__init__(self)
+
+    def __str__(self):
+        chitroll = randint(2,12)
+        if chitroll == 2:
+            cheffect = "Scratch and Dent"
+            chdescription = "The attack merely scratches the paint. There's no permanent damage."
+        elif chitroll == 3:
+            cheffect = "Engine"
+            chdescription = "The engine is hit. Oil leaks, pistons misfire, etc. Acceleration is halved (round down). This does not affect deceleration, however."
+        elif chitroll == 4:
+            cheffect = "Locomotion"
+            chdescription = "The wheels, tracks, or whatever have been hit. Halve the vehicle's Top Speed immediately. If the vehicle is pulled by animals, the shot hits one of them instead."
+        elif chitroll == 5:  #Need to make an additional roll to see what direction the vehicle can turn...
+            cheffect = "Controls"
+            troll = randint(1,2)
+            if troll == 1:
+                aturn = "left"
+            else:
+                aturn = "right"
+            chdescription = "The control system is hit. Until a Repair roll is made, the vehicle can only perform turns to the "+str(aturn)+". This may prohibit certain maneuvers as well."
+        elif chitroll >= 6 and chitroll <=8:
+            cheffect = "Chassis"
+            chdescription = "The vehicle suffers a hit in the body with no special effects."
+        elif chitroll == 9 or chitroll == 10:
+            cheffect = "Crew"
+            chdescription = "A random crew member is hit. The damage from the attack is rerolled. If the character is inside the vehicle, subtract the vehicle's Armor from the damage. Damage caused by an explosion affects all passengers in the vehicle."
+        elif chitroll == 11:
+            cheffect = "Weapon"
+            chdescription = "A random weapon on the side of the vehicle that was hit is destroyed and may no longer be used. If there is no weapon, this is a Chassis hit instead (The vehicle suffers a hit in the body with no special effects)."
+        else:
+            cheffect = "Wrecked"
+            chdescription = "The vehicle is wrecked and automatically goes Out of Control.<br><br><b>[Out of Control]</b> ==>"+str(ooc())
+        myStr = "["+cheffect+" ("+str(chitroll)+")] ==> "+chdescription
+        return myStr
+
+    def ooc(self):
+        return vcritooc(self)
+
+class swdhelps(std):
+    #Display help information for this die roller - it will list all the available commands, and how to use them
+    def __init__(self):
+        std.__init__(self)
+
+    def __str__(self):
+        myStr = "<table border='1' valign='top'>\
+        <tr>\
+            <td colspan='3'>This chart will show you the various commands you can use and what is required, etc.  The <i><b>italicized text</b></i> are optional variables.  Any text that is not italicized and is within parentheses is required.  About the only roll that has a required element is the Knockout Blow roll (kob).</td>\
+        </tr>\
+        <tr>\
+            <td align='center'><b>Die Command</b></td><td align='center' width='55%'><b>Description</b></td><td align='center'width='30%'><b>Example</b></td>\
+        </tr>\
+        <tr>\
+            <td><b>[fright(<i>monster's fear modifier</i>)]</b></td><td>Rolls on the <b>Fright Table</b>.  This command generates a number between 1 and 20 and displays the corresponding entry from the Fright Table.</td><td>[fright()]<br>[fright(6)]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[kob(#ofWounds,<i>hitLocation</i>)]</b></td><td>Rolls on the <b>Knockout Blow Table</b> as well as the <b>Injury Table</b> if necessary.  The number of wounds must be specified, however, the location only needs to be specified if a particular body part was targeted.  If a hit location was targeted, then the following codes should be used:<br>\
+                <ul>\
+                    <li>h = head</li>\
+                    <li>g = guts/other vital areas</li>\
+                    <li>c = crotch/groin</li>\
+                    <li>la = left arm</li>\
+                    <li>ra = right arm</li>\
+                    <li>ll = left leg</li>\
+                    <li>rl = right leg</li>\
+                </ul><br>If no hit location is specified, the hit location will be determined when the roll on the Injury Table is necessary.  When specifiying a hit locations, the code must be entered within double quotes.</td><td><b>3 wounds, no called shot</b><br>[kob(3)]<br><b>2 wounds to the head</b><br>[kob(2,\"h\")]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[ract(<i>Charisma Mods</i>)]</b></td><td>Rolls on the <b>Reaction Table</b>.  Will generate the initial reaction to the PCs.  If the Charisma modifiers are supplied, they will be taken into account as well.  Remember that this table is generally only consulted when the reaction of the NPC is comlpetely unknown to the GM.</td><td><b>Reaction no Charisma Mods</b><br>[ract()]<br><b>Reaction with +2 Charisma Mods</b><br>[ract(2)]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[vcrit()]</b></td><td>Rolls on the <b>Critical Hit Table</b> for vehicles.  If a roll on the Out of Control Chart is necessary, it will automatically roll on that table as well.</td><td>[vcrit()]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[ooc()]</b></td><td>Rolls on the <b>Out of Controll Table</b> for vehicles.  This roll will automatically determine any directions/movement rolls as well.</td><td>[ooc()]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[fortune()]</b></td><td>Rolls on the <b>Fortune Table</b> for the Showdown Skirmish rules.  This roll will automatically roll on the <b>Freak Event Table</b> if necessary</td><td>[fortune()]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[freak()]</b></td><td>Rolls on the <b>Freak Event Table</b>.</td><td>[freak()]</td>\
+        </tr>\
+        <tr>\
+            <td><b>[swdhelps()]</b></td><td>Displays this help list.</td><td>[swdhelps()]</td>\
+        </tr>\
+        </table>"
+        return myStr
+
+class fortune(std):
+    def __init___(self):
+        std.__init__(self)
+
+    def __str__(self):
+        forroll = randint(2,12)
+        if forroll == 2 or forroll == 12: #Need to roll on Freak Event Table
+            fortune = "Freak Event!"
+            fdescription = "Roll on the Freak Event Table.<br><br><b>[Freak Event Table]</b> ==> "+str(freak())
+        elif forroll == 3:
+            fortune = "Twist of Fate"
+            fdescription = "Take a benny from your opponent. If he does not have one, he must immediately remove any one Extra from play."
+        elif forroll == 4:
+            fortune = "The Quick and the Dead"
+            fdescription = "Swap one of your opponent's cards for any one of yours."
+        elif forroll == 5:
+            fortune = "Rally"
+            fdescription = "Pick any one unit on the board with Shaken figures. All those figures recover automatically."
+        elif forroll >= 6 and forroll <= 8:
+            fortune = "Hand of Fate"
+            fdescription = "Gain one extra benny."
+        elif forroll == 9:
+            fortune = "Close Call"
+            fdescription = "Any one of your opponent's units stumbles, becomes confused, or is otherwise disrupted. All its members suffer -2 to their trait rolls this round."
+        elif forroll == 10:
+            fortune = "Teamwork"
+            fdescription = "Pick any one other unit within 12\" of this one. Discard its Action Card. It acts on the Joker along with this unit, and gains the usual bonuses as well."
+        else:
+            fortune = "Out of Ammo"
+            fdescription = "Pick any one enemy unit. It's out of ammo or Power Points (your choice). If this result cannot be applied, you gain a benny instead."
+        myStr = "["+fortune+" ("+str(forroll)+")] ==>"+fdescription
+        return myStr
+
+    def freak(self):
+        return fortunefreak(self)
+
+class freak(std):
+    def __init__(self):
+        std.__init__(self)
+
+    def __str__(self):
+        feroll = randint(1,10)
+        if feroll == 1:
+            fevent = "Storm"
+            fedescription = "A sudden storm rolls in. Rain begins to pour and visibility is limited to 12\". All attack rolls are at -1, and black powder weapons don't work at all. The round after this event, all streams become impassable, even at fords. Only bridges remain."
+        elif feroll == 2:
+            fevent = "Fire!"
+            fedescription = "Fire breaks out on the board! Roll randomly among each occupied building, patch of trees, or other flammable terrain type. If none of these are occupied, roll randomly among all flammable terrain pieces. The entire building or forest catches fire this round and causes 2d6 damage to everything within. The fire continues for the rest of the game--unless a storm comes, which quenches it immediately.<br><br>At the beginning of each turn thereafter, roll 1d6 for each flammable structure within 4\" (adjacent buildings, another patch of forest, etc.). On a 4-6, that structure catches fire as well. Check to see if these new fires spread in the following rounds."
+        elif feroll == 3:
+            fevent = "Blood Ties"
+            fedescription = "One of the Wild Cards on the other side is related or has some other special bond with one of your heroes (a Wild Card of your choice). For the rest of the battle, these two won't attack each other directly unless there are no other targets on the board."
+        elif feroll == 4:
+            fevent = "Death of a Hero"
+            inspireroll = randint(1,2)
+            if inspireroll == 1:
+                fedescription ="The next time one of your Wild Cards dies, his noble sacrifice triggers new resolve in his companions.  When your next Wild Card is Incapacitated the rest of your force is inspired by his legacy and adds +1 to all their rolls until another of your Wild Cards is killed."
+            else:
+                fedescription = "The next time one of your Wild Cards dies, his noble sacrifice triggers bone-chilling dread in his companions. When your next Wild Card is Incapacitated the rest of your force is filled with dread. They subtract -1 from all their rolls for the rest of the game until an <i>enemy</i> Wild Card is slain."
+        elif feroll == 5:
+            fevent = "Fickle Fate"
+            fedescription = "Fate favors the underdog. The side with the fewest bennies draws until it has the same number as their foe. Place these in the common pool."
+        elif feroll == 6:
+            fevent = "Back from the Dead"
+            fedescription = "One of your dead was just knocked unconscious. He returns in the spot where he fell. If this is a Wild Card, he returns with but a single wound."
+        elif feroll == 7:
+            fevent = "Bitter Cold/Heat"
+            fedescription = "The weather heats up or cools down, depending on your environment. All troops become tired or bogged down and reduce their running rolls by half for the rest of the game."
+        elif feroll == 8:
+            fevent = "Battle Tested"
+            fedescription = "Any one of your units improves any one skill or attribute a die type immediately."
+        elif feroll == 9:
+            fevent = "The Fog"
+            fedescription = "Dense fog, mist, or smoke rolls drifts over the battlefield. Place two connected Large Burst Templates at the center of one randomly determined board edge. The fog drifts 2d6\" each round in a random direction (roll a d12 and read it like a clock facing). The fog \"bounces\" if it hits an edge in a random direction (so that it never leaves the field)."
+        else:
+            fevent = "Reinforcements"
+            fedescription = "A group of your most common currently-fielded troop type arrives on the field of battle! Place these troops in your deployment area. They act on the Joker this round and are dealt in normally hereafter."
+        myStr = "["+fevent+"("+str(feroll)+")] ==> "+fedescription
+        return myStr
+
+class rdm(std):  #If I get the time and the inspiration - I may try to incorporate a Random Table roller...  I need to think about this one.
+    def __init__(self):
+        std.__init__(self)
+
+    def __str__(self):
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/shadowrun.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,146 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: shadowrun.py
+# Author: Michael Edwards (AKA akoman)
+# Maintainer:
+# Version: 1.0
+#
+# Description: A modified form of the World of Darkness die roller to
+#              conform to ShadowRun rules-sets. Thanks to the ORPG team
+#              for the original die rollers.
+#              Thanks to tdb30_ for letting me think out loud with him.
+#         I take my hint from the HERO dieroller: It creates for wildly variant options
+#         Further, .vs and .open do not work together in any logical way. One method of
+#         chaining them results in a [Bad Dice Format] and the other results in a standard
+#         output from calling .open()
+
+#         vs is a classic 'comparison' method function, with one difference. It uses a
+#           c&p'ed .open(int) from die.py but makes sure that once the target has been exceeded
+#           then it stops rerolling. The overhead from additional boolean checking is probably
+#           greater than the gains from not over-rolling. The behaviour is in-line with
+#           Shadowrun Third Edition which recommends not rolling once you've exceeded the target
+#         open is an override of .open(int) in die.py. The reason is pretty simple. In die.py open
+#           refers to 'open-ended rolling' whereas in Shadowrun it refers to an 'Open Test' where
+#           the objective is to find the highest die total out of rolled dice. This is then generally
+#           used as the target in a 'Success Test' (for which .vs functions)
+
+__version__ = "1.0"
+
+from std import std
+from orpg.dieroller.base import *
+
+class shadowrun(std):
+    name = "shadowrun"
+
+    def __init__(self,source=[],target=2):
+        std.__init__(self,source)
+
+    def vs(self,target):
+        return srVs(self, target)
+
+    def open(self):
+        return srOpen(self)
+
+die_rollers.register(shadowrun)
+
+class srVs(std):
+    def __init__(self,source=[], target=2):
+        std.__init__(self, source)
+        # In Shadowrun, not target number may be below 2. All defaults are set to two and any
+        # thing lower is scaled up.
+        if target < 2:
+            self.target = 2
+        else:
+            self.target = target
+        # Shadowrun was built to use the d6 but in the interests of experimentation I have
+        # made the dieroller generic enough to use any die type
+        self.openended(self[0].sides)
+
+    def openended(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if (self.data[i].lastroll() >= num) and (self.data[i] < self.target):
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.openended(num)
+
+    def __sum__(self):
+        s = 0
+        for r in self.data:
+            if r >= self.target:
+                s += 1
+        return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            myStr += "] vs " + str(self.target) + " for a result of (" + str(self.sum()) + ")"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
+
+class srOpen(std):
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        self.openended(self[0].sides)
+
+    def openended(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() == num:
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.openended(num)
+
+    def __sum__(self):
+        s = 0
+        for r in self.data:
+            if r > s:
+                s = r
+        return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            self.takeHighest(1)
+            myStr += "] for a result of (" + str(self.__sum__().__int__()) + ")"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/sr4.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,237 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#   openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: sr4.py
+# Author: Veggiesama, ripped straight from Michael Edwards (AKA akoman)
+# Maintainer:
+# Version: 1.1
+#
+# 1.1: Now with glitch and critical glitch detection!
+# 1.1: Cleaned up some of the output to make it simpler.
+#
+# Description: Modified from the original Shadowrun dieroller by akoman,
+#              but altered to follow the new Shadowrun 4th Ed dice system.
+#
+#              SR4 VS
+#              Typing [Xd6.vs(Y)] will roll X dice, checking each die
+#              roll against the MIN_TARGET_NUMBER (default: 5). If it
+#              meets or beats it, it counts as a hit. If the total hits
+#              meet or beat the Y value (threshold), there's a success.
+#
+#              SR4 EDGE VS
+#              Identical to the above function, except it looks like
+#              [Xd6.edge(Y)] and follows the "Rule of Six". That rule
+#              states any roll of 6 is counted as a hit and rerolled
+#              with a potential to score more hits. The "Edge" bonus
+#              dice must be included into X.
+#
+#              SR4 INIT
+#              Typing [Xd6.init(Y)] will roll X dice, checking each
+#              die for a hit. All hits are added to Y (the init attrib
+#              of the player), to give an Init Score for the combat.
+#
+#              SR4 EDGE INIT
+#              Typing [Xd6.initedge(Y)] or [Xd6.edgeinit(Y)] will do
+#              as above, except adding the possibility of Edge dice.
+#
+#              Note about non-traditional uses:
+#              - D6's are not required. This script will work with any
+#                die possible, and the "Rule of Six" will only trigger
+#                on the highest die roll possible. Not throughly tested.
+#              - If you want to alter the minimum target number (ex.
+#                score a hit on a 4, 5, or 6), scroll down and change
+#                the global value MIN_TARGET_NUMBER to your liking.
+
+__version__ = "1.1"
+
+from std import std
+from orpg.dieroller.base import *
+
+MIN_TARGET_NUMBER = 5
+GLITCH_NUMBER = 1
+
+class sr4(std):
+    name = "sr4"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        self.threshold = None
+        self.init_attrib = None
+
+    def vs(self,threshold=0):
+        return sr4vs(self, threshold)
+
+    def edge(self,threshold=0):
+        return sr4vs(self, threshold, 1)
+
+    def init(self,init_attrib=0):
+        return sr4init(self, init_attrib)
+
+    def initedge(self,init_attrib=0):
+        return sr4init(self, init_attrib, 1)
+    def edgeinit(self,init_attrib=0):
+        return sr4init(self, init_attrib, 1)
+
+    def countEdge(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if (self.data[i].lastroll() >= num):
+                # counts every rerolled 6 as a hit
+                self.hits += 1
+                self.data[i].extraroll()
+                self.total += 1
+                done = 0
+            elif (self.data[i].lastroll() <= GLITCH_NUMBER):
+                self.ones += 1
+            self.total += 1
+        if done:
+            return self
+        else:
+            return self.countEdge(num)
+
+    def countHits(self,num):
+        for i in range(len(self.data)):
+            if (self.data[i].lastroll() >= MIN_TARGET_NUMBER):
+                # (Rule of Six taken into account in countEdge(), not here)
+                self.hits += 1
+            elif (self.data[i].lastroll() <= GLITCH_NUMBER):
+                self.ones += 1
+            self.total += 1
+
+    def __str__(self):
+        if len(self.data) > 0:
+            self.hits = 0
+            self.ones = 0
+            self.total = 0
+            for i in range(len(self.data)):
+                if (self.data[i].lastroll() >= MIN_TARGET_NUMBER):
+                    self.hits += 1
+                elif (self.data[i].lastroll() <= GLITCH_NUMBER):
+                    self.ones += 1
+                self.total += 1
+            firstpass = 0
+            myStr = "["
+            for a in self.data[0:]:
+                if firstpass != 0:
+                    myStr += ","
+                firstpass = 1
+                if a >= MIN_TARGET_NUMBER:
+                    myStr += "<B>" + str(a) + "</B>"
+                elif a <= GLITCH_NUMBER:
+                    myStr += "<i>" + str(a) + "</i>"
+                else:
+                    myStr += str(a)
+            myStr += "] " + CheckIfGlitch(self.ones, self.hits, self.total)
+            myStr += "Hits: (" + str(self.hits) + ")"
+        else:
+            myStr = "[] = (0)"
+        return myStr
+
+die_rollers.register(sr4)
+
+class sr4init(sr4):
+    def __init__(self,source=[],init_attrib=1,edge=0):
+        std.__init__(self,source)
+        if init_attrib < 2:
+            self.init_attrib = 2
+        else:
+            self.init_attrib = init_attrib
+        self.dicesides = self[0].sides
+        self.hits = 0
+        self.ones = 0
+        self.total = 0
+        if edge:
+            self.countEdge(self.dicesides)
+        self.countHits(self.dicesides)
+
+    def __str__(self):
+        if len(self.data) > 0:
+            firstpass = 0
+            myStr = "["
+            for a in self.data[0:]:
+                if firstpass != 0:
+                    myStr += ","
+                firstpass = 1
+                if a >= MIN_TARGET_NUMBER:
+                    myStr += "<B>" + str(a) + "</B>"
+                elif a <= GLITCH_NUMBER:
+                    myStr += "<i>" + str(a) + "</i>"
+                else:
+                    myStr += str(a)
+            myStr += "] " + CheckIfGlitch(self.ones, self.hits, self.total)
+            init_score = str(self.init_attrib + self.hits)
+            myStr += "InitScore: " + str(self.init_attrib) + "+"
+            myStr += str(self.hits) + " = (" + init_score + ")"
+        else:
+            myStr = "[] = (0)"
+        return myStr
+
+class sr4vs(sr4):
+    def __init__(self,source=[], threshold=1, edge=0):
+        std.__init__(self, source)
+        if threshold < 0:
+            self.threshold = 0
+        else:
+            self.threshold = threshold
+        self.dicesides = self[0].sides
+        self.hits = 0
+        self.ones = 0
+        self.total = 0
+        if edge:
+            self.countEdge(self.dicesides)
+        self.countHits(self.dicesides)
+
+    def __str__(self):
+        if len(self.data) > 0:
+            firstpass = 0
+            myStr = "["
+            for a in self.data[0:]:
+                if firstpass != 0:
+                    myStr += ","
+                firstpass = 1
+                if a >= MIN_TARGET_NUMBER:
+                    myStr += "<B>" + str(a) + "</B>"
+                elif a <= GLITCH_NUMBER:
+                    myStr += "<i>" + str(a) + "</i>"
+                else:
+                    myStr += str(a)
+            #myStr += "] Threshold=" + str(self.threshold)
+            myStr += "] vs " + str(self.threshold) + " "
+            myStr += CheckIfGlitch(self.ones, self.hits, self.total)
+            if self.hits >= self.threshold:
+                myStr += "*SUCCESS* "
+            else:
+                myStr += "*FAILURE* "
+            myStr += "Hits: (" + str(self.hits) + ")"
+        else:
+            myStr = "[] = (0)"
+        return myStr
+
+def CheckIfGlitch(ones, hits, total_dice):
+    if (ones * 2) >= total_dice:
+        if hits >= 1:
+            return "*GLITCH* "
+        else:
+            return "*CRITICAL GLITCH* "
+    else:
+        return ""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/srex.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,197 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: srex.py
+# Original Author: Michael Edwards (AKA akoman)
+# Maintainer:
+# Original Version: 1.0
+#
+# Description: A modified form of the World of Darkness die roller to
+#              conform to ShadowRun rules-sets. Thanks to the ORPG team
+#              for the original die rollers.
+#              Thanks to tdb30_ for letting me think out loud with him.
+#         I take my hint from the HERO dieroller: It creates for wildly variant options
+#         Further, .vs and .open do not work together in any logical way. One method of
+#         chaining them results in a [Bad Dice Format] and the other results in a standard
+#         output from calling .open()
+
+#         vs is a classic 'comparison' method function, with one difference. It uses a
+#           c&p'ed .open(int) from die.py but makes sure that once the target has been exceeded
+#           then it stops rerolling. The overhead from additional boolean checking is probably
+#           greater than the gains from not over-rolling. The behaviour is in-line with
+#           Shadowrun Third Edition which recommends not rolling once you've exceeded the target
+#         open is an override of .open(int) in die.py. The reason is pretty simple. In die.py open
+#           refers to 'open-ended rolling' whereas in Shadowrun it refers to an 'Open Test' where
+#           the objective is to find the highest die total out of rolled dice. This is then generally
+#           used as the target in a 'Success Test' (for which .vs functions)
+
+# Modified by: Darloth
+# Mod Version: 1.1
+# Modified Desc:
+#       I've altered the vs call to make it report successes against every target number (tn)
+#       in a specified (default 3) range, with the original as median.
+#       This reduces rerolling if the TN was calculated incorrectly, and is also very useful
+#       when people are rolling against multiple TNs, which is the case with most area-effect spells.
+#       To aid in picking the specified TN out from the others, it will be in bold.
+#       vswide is a version which can be used with no arguments, or can be used to get a very wide range, by
+#       directly specifying the upper bound (Which is limited to 30)
+
+from std import std
+from orpg.dieroller.base import *
+
+__version__ = "1.1"
+
+class srex(std):
+    name = "srex"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+    def vs(self,actualtarget=4,tnrange=3):        #reports all tns around specified, max distance of range
+        return srVs(self,actualtarget,(actualtarget-tnrange),(actualtarget+tnrange))
+
+    def vswide(self,actualtarget=4,maxtarget=12):    #wide simply means it reports TNs from 2 to a specified max.
+        return srVs(self,actualtarget,2,maxtarget)
+
+    def open(self):         #unchanged from standard shadowrun open.
+        return srOpen(self)
+
+die_rollers.register(srex)
+
+class srVs(std):
+    def __init__(self,source=[],actualtarget=4,mintn=2,maxtn=12):
+        std.__init__(self, source)
+        if actualtarget > 30:
+            actualtarget = 30
+        if mintn > 30:
+            mintn = 30
+        if maxtn > 30:
+            maxtn = 30
+        # In Shadowrun, not target number may be below 2. Any
+        # thing lower is scaled up.
+        if actualtarget < 2:
+            self.target = 2
+        else:
+            self.target = actualtarget
+        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
+        if actualtarget > maxtn:
+            maxtn = actualtarget
+        #store minimum for later use as well, also in result printing section.
+        if mintn < 2:
+            self.mintn = 2
+        else:
+            self.mintn = mintn
+        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
+
+        # Shadowrun was built to use the d6 but in the interests of experimentation I have
+        # made the dieroller generic enough to use any die type
+        self.openended(self[0].sides)
+
+    def openended(self,num):
+        if num <= 1:
+            self
+        done = 1
+
+        #reroll dice if they hit the highest number, until they are greater than the max TN (recursive)
+        for i in range(len(self.data)):
+            if (self.data[i].lastroll() >= num) and (self.data[i] < self.maxtn):
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.openended(num)
+
+    #count successes, by looping through each die, and checking it against the currently set TN
+    def __sum__(self):
+        s = 0
+        for r in self.data:
+            if r >= self.target:
+                s += 1
+        return s
+
+    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
+    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
+    #easily be lost.
+    def xsum(self,curtarget):
+        s = 0
+        for r in self.data:
+            if r >= curtarget:
+                s += 1
+        return s
+
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            myStr += "] Results: "
+            #cycle through from mintn to maxtn, summing successes for each separate TN
+            for targ in range(self.mintn,self.maxtn+1):
+                if targ == self.target:
+                    myStr += "<b>"
+                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
+                if targ == self.target:
+                    myStr += "</b>"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
+
+class srOpen(std):
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        self.openended(self[0].sides)
+
+    def openended(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() == num:
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.openended(num)
+
+    def __sum__(self):
+        s = 0
+        for r in self.data:
+            if r > s:
+                s = r
+        return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            self.takeHighest(1)
+            myStr += "] for a result of (" + str(self.__sum__().__int__()) + ")"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/std.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,83 @@
+from orpg.dieroller.base import die_base, die_rollers
+
+class std(die_base):
+    name = "std"
+
+    def __init__(self,source=[]):
+        die_base.__init__(self,source)
+
+    #  Examples of adding member functions through inheritance.
+
+    def ascending(self):
+        result = self[:]
+        result.sort()
+        return result
+
+    def descending(self):
+        result = self[:]
+        result.sort()
+        result.reverse()
+        return result
+
+    def takeHighest(self,num_dice):
+        return self.descending()[:num_dice]
+
+    def takeLowest(self,num_dice):
+        return self.ascending()[:num_dice]
+
+    def extra(self,num):
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() >= num:
+                self.data[i].extraroll()
+        return self
+
+    def open(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() >= num:
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.open(num)
+
+    def minroll(self,min):
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() < min:
+                self.data[i].roll(min)
+        return self
+
+    def each(self,mod):
+        mod = int(mod)
+        for i in range(len(self.data)):
+            self.data[i].modify(mod)
+        return self
+
+
+    def vs(self, target):
+        for dn in self.data:
+            dn.target = target
+        return self
+
+
+    ## If we are testing against a saving throw, we check for
+    ## greater than or equal to against the target value and
+    ## we only return the number of successful saves.  A negative
+    ## value will never be generated.
+    def sum(self):
+        retValue = 0
+        for dn in self.data:
+            setValue = reduce( lambda x, y : int(x)+int(y), dn.history )
+            if dn.target:
+                if setValue >= dn.target:
+                    retValue += 1
+
+            else:
+                retValue += setValue
+
+        return retValue
+
+die_rollers.register(std)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/trinity.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,88 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: trinity.py
+# Author: Jacob Matthew, Talisan Creations
+# Maintainer:
+# Version:
+#   $Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $
+#
+# Description: Aeon Trinity die roller
+# Modified from the WoD dieroller "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
+# Targetthr is the Threshhold target
+# for compatibility with Mage die rolls.
+# Threshhold addition by robert t childers
+# Threshhold functionality removed, some tags remain in code.
+
+__version__ = "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
+
+from std import std
+from orpg.dieroller.base import *
+
+class trinity(std):
+    name = "trinity"
+
+    def __init__(self,source=[],target=7,targetthr=0):
+        std.__init__(self,source)
+        self.target = target
+        self.targetthr = targetthr
+
+    def vs(self,target):
+        self.target = target
+        return self
+
+    def thr(self,targetthr):
+        self.targetthr = targetthr
+        return self
+
+    def sum(self):
+        rolls = []
+        s = 0
+        b = 0
+        for a in self.data:
+            rolls.extend(a.gethistory())
+        for r in rolls:
+            if r >= self.target:
+                s += 1
+            elif r == 1:
+                b -= 1
+        if s == 0:
+            return b
+        else:
+            return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            if self.sum() < 0:
+                myStr += "] result of a (" + str(self.sum()) + ") botch"
+            elif self.sum() == 0:
+                myStr += "] result of a failure"
+            else:
+                myStr += "] result of (" + str(self.sum()) + ") success"
+
+
+        return myStr
+
+die_rollers.register(trinity)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/wod.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,92 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: wod.py
+# Author: OpenRPG Dev Team
+# Maintainer:
+# Version:
+#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#
+# Description: WOD die roller
+#
+# Targetthr is the Threshhold target
+# for compatibility with Mage die rolls.
+# Threshhold addition by robert t childers
+
+__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+
+from std import std
+from orpg.dieroller.base import *
+
+class wod(std):
+    name = "wod"
+
+    def __init__(self,source=[],target=0,targetthr=0):
+        std.__init__(self,source)
+        self.target = target
+        self.targetthr = targetthr
+
+    def vs(self,target):
+        self.target = target
+        return self
+
+    def thr(self,targetthr):
+        self.targetthr = targetthr
+        return self
+
+    def sum(self):
+        rolls = []
+        s = 0
+        s1 = self.targetthr
+        botch = 0
+        for a in self.data:
+            rolls.extend(a.gethistory())
+        for r in rolls:
+            if r >= self.target or r == 10:
+                s += 1
+                if s1 >0:
+                    s1 -= 1
+                    s -= 1
+                else:
+                    botch = 1
+            elif r == 1:
+                s -= 1
+            if botch == 1 and s < 0:
+                s = 0
+        return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            if self.sum() < 0:
+                myStr += "] vs " +str(self.target)+" result of a botch"
+            elif self.sum() == 0:
+                myStr += "] vs " +str(self.target)+" result of a failure"
+            else:
+                myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
+
+
+        return myStr
+
+die_rollers.register(wod)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/wodex.py	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,291 @@
+## a vs die roller as used by WOD games
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: wodex.py
+# Original Author: Darloth
+# Maintainer:
+# Original Version: 1.0
+#
+# Description: A modified form of the World of Darkness die roller to
+#              conform to ShadowRun rules-sets, then modified back to the WoD for
+#              the new WoD system. Thanks to the ORPG team
+#              for the original die rollers.
+#              Much thanks to whoever wrote the original shadowrun roller (akoman I believe)
+
+
+from std import std
+from orpg.dieroller.base import *
+
+__version__ = "$Id: wodex.py,v 1.9 2007/05/06 16:42:55 digitalxero Exp $"
+
+class wodex(std):
+    name = "wodex"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+    def vs(self,actualtarget=6):
+        return oldwodVs(self,actualtarget,(6))
+
+    def wod(self,actualtarget=8):
+        return newwodVs(self,actualtarget,(8))
+
+    def exalt(self, actualtarget=7):
+        return exaltVs(self, actualtarget)
+
+    def exaltDmg(self, actualtarget=7):
+        return exaltDmg(self, actualtarget)
+
+    def vswide(self,actualtarget=6,maxtarget=10):    #wide simply means it reports TNs from 2 to a specified max.
+        return oldwodVs(self,actualtarget,2,maxtarget)
+
+die_rollers.register(wodex)
+
+class oldwodVs(std):
+    def __init__(self,source=[],actualtarget=6,mintn=2,maxtn=10):
+        std.__init__(self, source)
+        if actualtarget > 10:
+            actualtarget = 10
+        if mintn > 10:
+            mintn = 10
+        if maxtn > 10:
+            maxtn = 10
+        if actualtarget < 2:
+            self.target = 2
+        else:
+            self.target = actualtarget
+        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
+        if actualtarget > maxtn:
+            maxtn = actualtarget
+        if actualtarget < mintn:
+            mintn = actualtarget
+        #store minimum for later use as well, also in result printing section.
+        if mintn < 2:
+            self.mintn = 2
+        else:
+            self.mintn = mintn
+        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
+
+        # WoD etc uses d10 but i've left it so it can roll anything openended
+        # self.openended(self[0].sides)
+
+    #count successes, by looping through each die, and checking it against the currently set TN
+    #1's subtract successes.
+    def __sum__(self):
+        s = 0
+        for r in self.data:
+            if r >= self.target:
+                s += 1
+            elif r == 1:
+                s -= 1
+        return s
+
+    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
+    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
+    #easily be lost. 1s subtract successes from everything.
+    def xsum(self,curtarget):
+        s = 0
+        for r in self.data:
+            if r >= curtarget:
+                s += 1
+            elif r == 1:
+                s -= 1
+        return s
+
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            myStr += "] Results: "
+            #cycle through from mintn to maxtn, summing successes for each separate TN
+            for targ in range(self.mintn,self.maxtn+1):
+                if (targ == self.target):
+                    myStr += "<b>"
+                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
+                if (targ == self.target):
+                    myStr += "</b>"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
+
+class newwodVs(std):
+    def __init__(self,source=[],actualtarget=8,mintn=8,maxtn=8):
+        std.__init__(self, source)
+        if actualtarget > 30:
+            actualtarget = 30
+        if mintn > 10:
+            mintn = 10
+        if maxtn > 10:
+            maxtn = 10
+        if actualtarget < 2:
+            self.target = 2
+        else:
+            self.target = actualtarget
+        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
+        if actualtarget > maxtn:
+            maxtn = actualtarget
+        if actualtarget < mintn:
+            mintn = actualtarget
+        #store minimum for later use as well, also in result printing section.
+        if mintn < 2:
+            self.mintn = 2
+        else:
+            self.mintn = mintn
+        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
+
+        # WoD etc uses d10 but i've left it so it can roll anything openended
+        # self.openended(self[0].sides)
+
+    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
+    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
+    #easily be lost. 1s subtract successes from original but not re-rolls.
+    def xsum(self,curtarget,subones=1):
+        s = 0
+        done = 1
+        for r in self.data:
+            if r >= curtarget:
+                s += 1
+            elif ((r == 1) and (subones == 1)):
+                s -= 1
+        if r == 10:
+            done = 0
+            subones = 0
+            self.append(di(10))
+        if done == 1:
+            return s
+        else:
+            return self.xsum(0)
+
+    def openended(self,num):
+        if num <= 1:
+            self
+        done = 1
+        for i in range(len(self.data)):
+            if self.data[i].lastroll() == num:
+                self.data[i].extraroll()
+                done = 0
+        if done:
+            return self
+        else:
+            return self.openended(num)
+
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = "[" + str(self.data[0])
+            for a in self.data[1:]:
+                myStr += ","
+                myStr += str(a)
+            myStr += "] Results: "
+            #cycle through from mintn to maxtn, summing successes for each separate TN
+            for targ in range(self.mintn,self.maxtn+1):
+                if (targ == self.target):
+                    myStr += "<b>"
+                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
+                if (targ == self.target):
+                    myStr += "</b>"
+        else:
+            myStr = "[] = (0)"
+
+        return myStr
+
+class exaltVs(std):
+    def __init__(self, source=[], actualtarget=7):
+        std.__init__(self, source)
+
+        if actualtarget > 10:
+            actualtarget = 10
+
+        if actualtarget < 2:
+            self.target = 2
+        else:
+            self.target = actualtarget
+
+
+    def xsum(self, target):
+        s = 0
+
+        for r in self.data:
+            if r >= target:
+                s += 1
+            if r == 10:
+                s += 1
+
+        return s
+
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = str(self.data)
+            myStr += " Results: "
+
+            succ = self.xsum(self.target)
+            if succ == 0 and 1 in self.data:
+                myStr += 'BOTCH!'
+            elif succ == 0:
+                myStr += str(succ) + " Failure"
+            elif succ == 1:
+                myStr += str(succ) + " Success"
+            else:
+                myStr += str(succ) + " Successes"
+
+            return myStr
+
+class exaltDmg(std):
+    def __init__(self, source=[], actualtarget=7):
+        std.__init__(self, source)
+        if actualtarget > 10:
+            actualtarget = 10
+
+        if actualtarget < 2:
+            self.target = 2
+        else:
+            self.target = actualtarget
+
+    def xsum(self, target):
+        s = 0
+
+        for r in self.data:
+            if r >= target:
+                s += 1
+        return s
+
+    def __str__(self):
+        if len(self.data) > 0:
+            myStr = str(self.data)
+            myStr += " Results: "
+
+            succ = self.xsum(self.target)
+
+            if succ == 0 and 1 in self.data:
+                myStr += 'BOTCH!'
+            elif succ == 0:
+                myStr += str(succ) + " Failure"
+            elif succ == 1:
+                myStr += str(succ) + " Success"
+            else:
+                myStr += str(succ) + " Successes"
+
+            return myStr
--- a/orpg/dieroller/runequest.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,740 +0,0 @@
-
-
-
-
-# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-#-------------------------------------------------------------------------
-#
-#  Usage:
-#
-#   Die  Roller: /dieroller rq
-#
-#   Skill  Roll: [1d100.skill(50,0,0)]         # ( skill%, modifer, MA% )
-#
-#   Parry  Roll: [1d100.parry(50,0,0,12)]      # ( skill%, modifer, MA%, Weapon/Shield AP )
-#
-#   Dodge  Roll: [1d100.parry(50,0,0)]         # ( skill%, modifer, MA% )
-#
-#   Attack Roll: [1d100.attack(50,0,0,2,9,3,0)]
-#       ( skill%, modifer, MA%, min weap dam, max weap dam, dam bonus, truesword )
-#
-#   Sorcery Roll: [1d100.sorcery(90,   0,   3,   6,   1,   1,    1)]
-#                               (sk, mod, pow, cer, int,  acc, mlt)
-#
-#
-#
-#   Skill Training Unlimited Roll: [1d100.trainskill(30,75)]       # (starting skill%, desired skill%)
-#   Skill Training Cost Limited:   [1d100.trainskillcost(1000, 50) # (payment, starting skill%)
-#   Skill Training Time Limited:   [1d100.trainskilltime(150, 50)  # (time, strting skill%)
-#
-#-------------------------------------------------------------------------
-# --
-#
-# File: rq.py
-# Version:
-#   $Id: rq.py,v .1 pelwer
-#
-# Description: Runequest die roller originally based on Heroman's Hero Dieroller
-#
-#
-# v.1 - pelwer - 2/5/2005
-#  o Original release
-# v.2 - pelwer - 10/30/2006
-#  o Ported to openrpg+ by removing dependance on whrandom
-#  o Fixed Riposte spelling
-#  o Deleted sorcalc - never used
-#  o Added Sorcery Fumble table to sorcery spell roller
-#
-
-from die import *
-from time import time, clock
-import random
-from math import floor
-
-__version__ = "$Id: runequest.py,v 1.4 2006/11/15 12:11:22 digitalxero Exp $"
-
-# rq stands for "Runequest"
-
-class runequest(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-    # these methods return new die objects for specific options
-
-    
-    def skill(self,sk,mod,ma):
-        return rqskill(self,sk,mod,ma)
-
-    
-    def parry(self,sk,mod,ma,AP):
-        return rqparry(self,sk,mod,ma,AP)
-
-    
-    def dodge(self,sk,mod,ma):
-        return rqdodge(self,sk,mod,ma)
-
-    
-    def attack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd):
-        return rqattack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd)
-
-    
-    def sorcery(self,sk,mod,pow,cer,int,acc,mlt):
-        return rqsorcery(self,sk,mod,pow,cer,int,acc,mlt)
-
-    
-    def trainskill(self,initial,final):
-        return rqtrainskill(self,initial,final)
-
-    
-    def trainskillcost(self,cost,sk):
-        return rqtrainskillcost(self,cost,sk)
-
-    
-    def trainskilltime(self,time,sk):
-        return rqtrainskilltime(self,time,sk)
-
-#  RQ Skill Training Cost/Time unlimited
-#
-# [1d100.trainskill(10,20)]
-#          initial skill%, final skill%
-#
-# sk    = skill %
-#
-#
-class rqtrainskill(std):
-    
-    def __init__(self,source=[],initial=11,final=0):
-        std.__init__(self,source)
-        self.s = initial
-        self.f = final
-
-    
-    def __str__(self):
-        myStr = "Unrestricted Training"
-
-        if self.s == 0:
-            myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
-        else:
-            cost  = 0
-            time  = 0
-            myStr = "Training: "
-
-            while self.s < self.f and self.s < 75:
-                cost   += self.s * 5
-                time   += self.s * 1
-                self.s += random.uniform(1,4) + 1
-
-            myStr  = "Training completed:\n"
-            myStr += "\tCost(" + str(int(cost)) + ")\n"
-            myStr += "\tTime(" + str(int(time)) + ")\n"
-            myStr += "\tSkill(" + str(int(self.s)) + ")"
-
-        return myStr
-
-
-#  RQ Skill Training Cost Limited
-#
-# [1d100.trainskillcost(50,0)]
-#          cost, skill%
-#
-# cost  = cash for training
-# sk    = skill %
-#
-#
-class rqtrainskillcost(std):
-    
-    def __init__(self,source=[],cost=11,sk=0):
-        std.__init__(self,source)
-        self.cost = cost
-        self.sk   = sk
-
-    
-    def __str__(self):
-        myStr = ""
-
-        if self.sk == 0 and self.cost >= 50:
-            myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
-        else:
-            cost  = 0
-            time  = 0
-            icost = self.sk * 5
-
-            myStr = "Training: "
-
-            while (cost + icost) < self.cost:
-                if self.sk >= 75:
-                    break
-
-                cost += icost
-                time += self.sk * 1
-                self.sk += random.uniform(1,4) + 1
-                icost = self.sk * 5
-
-            myStr  = "Training completed: "
-            myStr += "Cost(" + str(int(cost)) + ") "
-            myStr += "Time(" + str(int(time)) + ") "
-            myStr += "Skill(" + str(int(self.sk)) + ")"
-
-        return myStr
-
-
-#  RQ Skill Training Time Limited
-#
-# [1d100.trainskilltime(50,0)]
-#          time, skill%
-#
-# time  = time for training
-# sk    = skill %
-#
-#
-class rqtrainskilltime(std):
-    
-    def __init__(self,source=[],time=11,sk=0):
-        std.__init__(self,source)
-        self.time = time
-        self.sk   = sk
-
-    
-    def __str__(self):
-        myStr = ""
-
-        if self.sk == 0 and self.time >= 20:
-            myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
-        else:
-            cost  = 0
-            time  = 0
-            itime = self.sk * 1
-
-            myStr = "Trainingsss: "
-
-            while (time + itime) < self.time:
-                if self.sk >= 75:
-                    break
-
-                cost += self.sk * 5
-                time += itime
-                self.sk += random.uniform(1,4) + 1
-                itime = self.sk * 5
-
-            myStr  = "Training completed: "
-            myStr += "Cost(" + str(int(cost)) + ") "
-            myStr += "Time(" + str(int(time)) + ") "
-            myStr += "Skill(" + str(int(self.sk)) + ")"
-
-        return myStr
-
-#  RQ Skill Roll
-#
-# [1d100.skill(50,0,0)]
-#          skill%, modifer, ma%
-#
-# sk    = skill %
-# mod   = modifier %
-# ma    = martial arts %
-# skill = sk + mod
-#
-# success   roll <= skill
-#
-# failure   roll > skill
-#
-# crit
-#     push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( skill/20 ) );
-#
-# special
-#     push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( $skill/5 ) );
-#
-# fumble: if ( $skill > 100 ) { $fum = 0; } else { $fum = 100 - $skill; }
-#             $fum = 100 - POSIX::floor( $fum/20 );
-#             if ( $fum == 100 ) { $fum = '00'; };
-#
-class rqskill(std):
-    
-    def __init__(self,source=[],sk=11,mod=0,ma=0):
-        std.__init__(self,source)
-        self.sk  = sk
-        self.mod = mod
-        self.ma  = ma
-
-    
-    def is_success(self):
-        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
-
-    
-    def is_ma(self):
-        return (self.sum() <= self.ma)
-
-    
-    def is_special(self):
-        return (self.sum() <= int(floor((self.sk + self.mod)/5)))
-
-    
-    def is_critical(self):
-        return (self.sum() <= int(floor((self.sk + self.mod) / 20)))
-
-    
-    def is_fumble(self):
-        if ( self.sk >= 100 ):
-            fum = 0
-        else:
-            fum = (100 - self.sk )
-        final_fum = ( 100 - int( floor( fum/20  ) ) )
-        return (  self.sum() >= final_fum )
-
-    
-    def __str__(self):
-        strAdd="+"
-        swapmod= self.mod
-        if self.mod < 0:
-            strAdd= "-"
-            swapmod= -self.mod
-        modSum = self.sum()
-        # build output string
-        myStr = " (" + str(modSum) + ")"
-        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
-        if self.is_fumble(): myStr += " <b><font color=red>Fumble!</font></b>"
-        elif self.is_critical(): myStr += " <b><font color=green>Critical!</font></b>"
-        elif self.is_special(): myStr += " <i><font color=green>Special!</font></i>"
-        elif self.is_success() and self.is_ma(): myStr += " <i><font color=green>Special!</font></i>"
-        elif self.is_success(): myStr += " <font color=blue>Success!</font>"
-        else: myStr += " <font color=red>Failure!</font>"
-
-        Diff = self.sk - modSum
-        myStr += " </font>"
-
-        return myStr
-
-#
-# RQ Parry Roll
-#
-# same as skill but with fumble dice and armor points
-#
-# [1d100.parry(50,0,0,12)]
-#             skill%, modifer, ma%, Weapon AP
-#
-
-class rqparry(std):
-    
-    def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
-        std.__init__(self,source)
-        self.sk = sk
-        self.mod = mod
-        self.ma  = ma
-        self.AP = AP
-
-    
-    def is_success(self):
-        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
-
-    
-    def is_special(self):
-        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
-
-    
-    def is_ma(self):
-        return (self.sum() <= self.ma)
-
-    
-    def is_riposte(self):
-        return (self.sum() <= (self.ma / 5))
-
-    
-    def is_critical(self):
-        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
-
-    
-    def is_fumble(self):
-        if ( self.sk >= 100 ):
-            fum = 0
-        else:
-            fum = (100 - self.sk )
-        final_fum = ( 100 - int( floor( fum/20  ) ) )
-        return (  self.sum() >= final_fum )
-
-    
-    def __str__(self):
-
-        # get fumble roll result in case needed
-        fum_roll = random.randint(1,100)
-
-        # get special AP
-        spec_AP = int( floor ( self.AP * 1.5 ) )
-
-        # figure out +/- for modifer
-        strAdd="+"
-        swapmod= self.mod
-        if self.mod < 0:
-            strAdd= "-"
-            swapmod= -self.mod
-        modSum = self.sum()
-
-        # build output string
-        myStr = " (" + str(modSum) + ")"
-        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
-        if self.is_fumble():
-            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
-        elif self.is_critical() and self.is_riposte():
-            myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
-            myStr += " Riposte next SR"
-        elif self.is_critical():
-         myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
-        elif self.is_special and self.is_riposte():
-            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
-            myStr += " Riposte next SR"
-        elif self.is_special():
-            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
-        elif self.is_success() and self.is_ma():
-            myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
-        elif self.is_success():
-            myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
-        else:
-            myStr += " <font color=red>Failure!</font>"
-
-        Diff = self.sk - modSum
-        myStr += " </font>"
-
-        return myStr
-
-# RQ Dodge Roll
-#
-# same as skill but with fumble dice and armor points
-#
-# [1d100.parry(50,0,0)]
-#             skill%, modifer, ma%
-#
-
-class rqdodge(std):
-    
-    def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
-        std.__init__(self,source)
-        self.sk = sk
-        self.mod = mod
-        self.ma  = ma
-        self.AP = AP
-
-    
-    def is_success(self):
-        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
-
-    
-    def is_special(self):
-        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
-
-    
-    def is_ma(self):
-        return (self.sum() <= self.ma)
-
-    
-    def is_riposte(self):
-        return (self.sum() <= (self.ma / 5))
-
-    
-    def is_critical(self):
-        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
-
-    
-    def is_fumble(self):
-        if ( self.sk >= 100 ):
-            fum = 0
-        else:
-            fum = (100 - self.sk )
-        final_fum = ( 100 - int( floor( fum/20  ) ) )
-        return (  self.sum() >= final_fum )
-
-    
-    def __str__(self):
-
-        # get fumble roll result in case needed
-        fum_roll = random.randint(1,100)
-
-        # get special AP
-        spec_AP = int( floor ( self.AP * 1.5 ) )
-
-        # figure out +/- for modifer
-        strAdd="+"
-        swapmod= self.mod
-        if self.mod < 0:
-            strAdd= "-"
-            swapmod= -self.mod
-        modSum = self.sum()
-
-        # build output string
-        myStr = " (" + str(modSum) + ")"
-        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
-        if self.is_fumble():
-            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
-        elif self.is_critical() and self.is_riposte():
-            myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
-            myStr += " Riposte on next SR"
-        elif self.is_critical():
-            myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
-        elif self.is_special and self.is_riposte():
-            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
-            myStr += " Riposte on next SR"
-        elif self.is_special():
-            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
-        elif self.is_success() and self.is_ma():
-            myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
-        elif self.is_success():
-            myStr += " <font color=blue>Success!</font> Damage dodged</b>"
-        else:
-            myStr += " <font color=red>Failure!</font>"
-
-        Diff = self.sk - modSum
-        myStr += " </font>"
-
-        return myStr
-
-
-
-#
-# RQ Attack Roll
-#
-# same as skill but with fumble dice and armor points
-#
-# [1d100.attack(50,0,0,2,9,3,1)]
-#             skill%, modifer, ma%, min weap dam, max weap dam, dam bonus, truesword_enabled
-#
-class rqattack(std):
-    
-    def __init__(self,source=[],sk=11,mod=0,ma=0,mindam=0,maxdam=0,bondam=0,trueswd=0):
-        std.__init__(self,source)
-        self.sk = sk
-        self.mod = mod
-        self.ma  = ma
-        self.mindam = mindam
-        self.maxdam = maxdam
-        self.bondam = bondam
-        self.trueswd = trueswd
-
-    
-    def is_success(self):
-        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
-
-    
-    def is_ma(self):
-        return (self.sum() <= self.ma)
-
-    
-    def is_special(self):
-        return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
-
-    
-    def is_critical(self):
-        return ((self.sum() <= int(floor((self.sk + self.mod) / 20))))
-
-    
-    def is_supercritical(self):
-        return (self.sum() == 1)
-
-    
-    def is_fumble(self):
-        if ( self.sk >= 100 ):
-            fum = 0
-        else:
-            fum = (100 - self.sk )
-        final_fum = ( 100 - int( floor( fum/20  ) ) )
-        return (  self.sum() >= final_fum )
-
-    
-    def __str__(self):
-
-        # get fumble roll result in case needed
-        fum_roll = random.randint(1,100)
-
-        # get hit location roll result in case needed
-        location = random.randint(1,20)
-        myStr = " to the ["+ str(location) + "] "
-        if location < 5:
-            myStr += "<B>Right Leg</B>"
-        elif location < 9:
-            myStr += "<B>Left Leg</B>"
-        elif location < 12:
-            myStr += "<B>Abdomen</B>"
-        elif location < 13:
-            myStr += "<B>Chest</B>"
-        elif location < 16:
-            myStr += "<B>Right Arm</B>"
-        elif location < 19:
-            myStr += "<B>Left Arm</B>"
-        else:
-            myStr += "<B>Head</B>"
-        hit_loc = myStr
-
-
-        # get normal damage in case needed
-        norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
-        norm_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
-        norm_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.bondam)
-        norm_damage_string += "}[" + str(norm_damage) + "] "
-
-        # get special/critical damage in case needed
-        crit_damage = random.randint( self.mindam*(self.trueswd+2), self.maxdam*(self.trueswd+2) ) + self.bondam
-        crit_damage_string = "{" + str( self.mindam*(self.trueswd+2) ) + "-" + str(self.maxdam*(self.trueswd+2)) + "+" + str(self.bondam) + "}[" + str(crit_damage) + "] "
-
-        # get supercritical damage in case needed
-        super_damage = norm_damage + self.maxdam
-        super_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
-        super_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.maxdam)
-        super_damage_string += "+" + str(self.bondam) + "}[" + str(super_damage) + "] "
-
-        # figure out +/- for modifer
-        strAdd="+"
-        swapmod= self.mod
-        if self.mod < 0:
-            strAdd= "-"
-            swapmod= -self.mod
-        modSum = self.sum()
-
-        # build output string
-        myStr = " (" + str(modSum) + ")"
-        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
-        if self.is_fumble():
-            myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
-        elif (self.is_supercritical() and self.is_success()):
-            myStr += " <b><font color=green>Super Critical!</font></b> Damage: " + str(super_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
-        elif (self.is_critical() and self.is_success()):
-            myStr += " <b><font color=green>Critical!</font></b> Damage: " + str(crit_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
-        elif ( self.is_special() and self.is_success() ):
-            myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
-        elif (self.is_success() and self.is_ma()):
-            myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
-        elif self.is_success():
-            myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
-        else:
-            myStr += " <font color=red>Failure!</font>"
-
-        return myStr
-
-#
-#
-#   Sorcery Roll: [1d100.sorcery(90,   10,  5,   4,   3,   2,    1)]
-#                               (sk, mod, pow, cer, int,  acc, mlt)
-#
-# Ceremony: (+1d6% per strike rank spent on ceremony)
-# Intensity: (-3% per point of Intensity)
-# Duration: (-4% per point of Duration)
-# Range: (-5% per point of Range)
-# Multispell: (-10% per each spell over 1)
-# Acceleration: (-5% per point of Acceleration)
-# Hold: (-2% per point in spell Held)
-#
-class rqsorcery(std):
-    
-    def __init__(self,source=[],sk=11,mod=0,pow=0,cer=0,int=0,acc=0,mlt=0):
-        std.__init__(self,source)
-        self.sk  = sk   # sorcery skill
-        self.mod = mod  # additional modifier ( from duration, range, etc )
-        self.pow = pow  # boost pow and additional pow ( from duration, range, etc )
-        self.cer = cer  # ceremony d6
-        self.int = int  # intensity ( -3% )
-        self.acc = acc  # accelerate ( -5% )
-        self.mlt = mlt  # multispell ( -10% )
-
-    
-    def is_success(self):
-        return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
-
-    
-    def is_special(self):
-        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/5  ) ) ) )
-
-    
-    def is_critical(self):
-        return ( (  self.sum() <= int( floor( ( self.sk + self.mod  )/20 ) ) ) )
-
-    
-    def is_fumble(self):
-        if ( self.sk >= 100 ):
-            fum = 0
-        else:
-            fum = (100 - self.sk )
-        final_fum = ( 100 - int( floor( fum/20  ) ) )
-        return (  self.sum() >= final_fum )
-
-    
-    def __str__(self):
-
-        # get fumble roll result in case needed
-        fum_roll = random.randint(2,12)
-        if fum_roll == 12 :
-            fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each day to remember.</font>"
-        if fum_roll == 11 :
-            fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each hour to remember.  </font>"
-        if fum_roll == 10 :
-            fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect.  </font>"
-        if fum_roll == 9 :
-            fum_string = "<br /><font color=purple>Caster is Stunned. Roll INTx3 to recover at SR 10 each round.  </font>"
-        if fum_roll == 8 :
-            fum_string = "<br /><font color=purple>Caster takes 2D6 Damage to THP  </font>"
-        if fum_roll == 7 :
-            fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect at 2x Intensity.  </font>"
-        if fum_roll == 6 :
-            fum_string = "<br /><font color=purple>Spell is cast on companions (if harmful) or on random nearby foes (if beneficial)  </font>"
-        if fum_roll == 5 :
-            fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to Head  </font>"
-        if fum_roll == 4 :
-            fum_string = "<br /><font color=purple>Spell is cast on caster (if harmful) or on random nearby foe (if beneficial)  </font>"
-        if fum_roll == 3 :
-            fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to THP  </font>"
-        if fum_roll == 2 :
-            fum_string = "<br /><font color=purple>Caster takes 1 point of Damage to Head  </font>"
-
-        # roll ceremony
-        ceremony_roll = random.randint( self.cer, (self.cer*6) )
-
-        # subtract manipulations
-        extra_mod = self.mod
-        self.mod += ceremony_roll - self.int*3 - self.acc*5 - self.mlt*10
-
-        # add up power cost
-        extra_pow = self.pow
-        self.pow += self.int + self.mlt + self.acc
-        special_pow = int( floor( ( self.pow )/2  ) )
-
-        # figure out +/- for modifer
-        strAdd="+"
-        swapmod= self.mod
-        if self.mod < 0:
-            strAdd= "-"
-            swapmod= -self.mod
-        modSum = self.sum()
-
-        # build output string
-        myStr = " (" + str(modSum) + ")"
-        myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
-        if self.is_fumble():
-            myStr += " <b><font color=red>Fumble!</font>  POW Cost: [" + str(self.pow) + "],</b> " + fum_string
-        elif self.is_critical():
-            myStr += " <b><font color=green>Critical!</font></b> POW Cost: [1] "
-        elif self.is_special():
-            myStr += " <i><font color=green>Special!</font></i> POW Cost: [" + str(special_pow) + "] "
-        elif self.is_success():
-            myStr += " <font color=blue>Success!</font> POW Cost: [" + str(self.pow) + "] "
-        else:
-            myStr += " <font color=red>Failure!</font> POW Cost: [1]"
-
-        # print spell details
-        myStr += "<br /> --- Other Modifiers:["    + str( extra_mod     ) + "], "
-        myStr += "Extra POW:[" + str( extra_pow     ) + "], "
-        myStr += "Ceremony:[+"          + str( ceremony_roll ) + "%], "
-        myStr += "Intensity(-3):["      + str( self.int      ) + "], "
-        myStr += "Accelerate(-5):["     + str( self.acc      ) + "], "
-        myStr += "Multispell(-10):["    + str( self.mlt      ) + "] ---"
-
-        return myStr
--- a/orpg/dieroller/savage.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,533 +0,0 @@
-# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: savage.py
-# Authors: Rich Finder
-#        : Alexandre Major
-# Maintainer:
-# Version: 0.2
-#
-# Description: Savage Worlds die roller
-# Permission was granted by Pinnacle to reprint the result descriptions from their tables on Apr 20, 2006 by Simon Lucas
-#
-
-from die import *
-import string
-from random import *
-__version__ = "$Id: savage.py,v 1.2 2007/05/06 16:42:55 digitalxero Exp $"
-
-# Savage, as in Savage Worlds
-class sw(std):
-    #def __init__(self,source=[], wnd=1, loc="rnd", chmod=0):
-    
-    def __init__(self,source=[],fmod=0):
-        std.__init__(self,source)
-
-# these methods return new die objects for specific options
-
-    
-    def fright(self,fearmod=0):
-        return fright(self,fearmod=0)
-
-    
-    def kob(self,wnd,loc):
-        return kob(self,wnd=1,loc="rnd")
-
-    
-    def ooc(self):
-        return ooc(self)
-
-    
-    def ract(self,chmod=0):
-        return ract(self,chmod=0)
-
-    
-    def vcrit(self):
-        return vcrit(self)
-
-    
-    def fortune(self):
-        return fortune(self)
-
-    
-    def freak(self):
-        return freak(self)
-
-    
-    def swdhelps(self):
-        return swdhelps(self)
-
-
-class fright(std):
-    #-----------------The Fright Table
-    #  Rolls on the Fright - which is a 1d20 roll modified by the fear level of a monster.  This function automatically generates
-    #  The appropriate random number and then adds the fear modifier to the rol and displays the result of the roll with the effect
-    #  of that roll.
-    #  Usage:  [fright()]
-    #          [fright(6)] - if the fear modifier of the monster was 6
-    #-----------------
-    
-    def __init__(self,fmod=0):
-        global fear
-        std.__init__(self)
-        fear=fmod
-
-    #def sum(self):
-
-    
-    def __str__(self):
-        global fear
-        iroll = randint(1,20)
-        froll = iroll + fear
-        if froll >= 1 and froll <=4:
-            fresult = "Adrenaline Rush"
-            fdescription = "The hero's \"fight\" response takes over.  He adds +2 to all Trait and damage rolls on his next action."
-        elif froll >= 5 and froll <=8:
-            fresult = "Shaken"
-            fdescription = "The character is Shaken."
-        elif froll >=9 and froll <=12:
-            fresult = "Pankicked"
-            fdescription = "The character immediately moves his full Pace plus running die away from the danger and is Shaken."
-        elif froll >=13 and froll <=16:
-            fresult = "Minor Phobia"
-            fdescription = "The character gains a Minor Phobia Hindrance somehow associated with the trauma."
-        elif froll >=17 and froll <=18:
-            fresult = "Major Phobia"
-            fdescription = "The character gains a Major Phobia Hindrance."
-        elif froll >=19 and froll <= 20:
-            fresult = "The Mark of Fear"
-            fdescription = "The hero is Shaken and also suffers some cosmetic, physical alteration -- a white streak forms in the hero's hair, his eyes twitch constantly, or some other minor physical alteration.  This reduces his Charisma by 1."
-        else:
-            fresult = "Heart Attack"
-            fdescription = "The hero is so overwhelmed with fear that his heart stutters.  He becomes Incapacitated and must make a Vigor roll at -2.  If Successful, he's Shaken and can't attempt to recover for 1d4 rounds.  If he fails, he dies in 2d6 rounds.  A Healing roll at -4 saves the victim's life, but he remains Incapacitated."
-        myStr = "[" + str(iroll) + "+"+str(fear)+"="+str(froll)+"] ==> " + fresult +":  "+ fdescription
-        return myStr
-
-class kob(std):
-    #-------------------The Knockout Blow Table
-    #  This table used when a character has sustained more than 3 wounds.  The number wounds taken that sends a character to the
-    #  Knockout Blow Table is what gets sent with the kob command - not the total number of wounds the character currently has.
-    #  For example - a character has 2 wounds and is hit takes 2 more wounds, this will result in a total of 4 wounds, but the
-    #  number that gets sent to the kob roll is 2, because that is the number of wounds sustained that sent the character to the kob
-    #  table.
-    #
-    #  It is also important to note that if a called shot to particular area was made, that information should be sent with the "roll"
-    #  as well, because the KOB Table may need to determine some dramatic effects for permanent injuries, etc.  If a hit location was sent
-    #  the function will use that information.
-    #  Valid Hit Locations are:  h (head), g (guts), la (left arm), ra (right arm), rl (right leg), ll (left leg), c (crotch)
-    #  Usage = [kob(3)] - If 3 wounds were received that sent the player to the Knockout Blow Table - no called shot
-    #          [kob(3,"h") - If 3 wounds were received that sent the player to the Knockout Blow Table with a called shot to the head
-    #---------------------
-    global wound, loca
-    
-    def __init__(self, wnd, loc="rnd"):
-        global wound, loca
-        std.__init__(self, wnd)
-        #Need to check to make sure that wnd is a number
-        if (int(wnd)):
-            wound = wnd
-            loca = loc
-        else:
-            mystr = "You need to supply a number for the wound."
-            return mystr
-
-    
-    def __str__(self):
-        global wound, loca
-        itbl = "no"
-        if wound == 1:
-            wtype = "Battered and Bruised"
-            wdescription = "If your hero was previously Incapacitated, this result has no further effect. Otherwise, your hero's had the wind knocked out of him. Make a Spirit roll at the beginning of each round. If the roll is successful, he becomes Shaken and can return to the fight."
-        elif wound == 2:  #Need to roll on the Injury table as well
-            wtype = "Incapacitated"
-            wdescription = "Your hero is beaten badly enough to take him out of this fight. He's Incapacitated and must roll on the Injury Table."
-            itbl = "yes"
-        elif wound == 3:
-            wtype = "Bleeding Out"
-            wdescription = "Your hero is bleeding out and Incapacitated. Roll on the Injury Table and make a Vigor roll at the start of each combat round. A failure means the hero has lost too much blood and becomes mortally Wounded (see below; begin rolling for the Mortal Wound in the next round). With a success, he keeps bleeding and must roll again next round. With a raise, or a successful Healing roll, he stops bleeding and is Incapacitated."
-            itbl = "yes"
-        elif wound < 1:
-            wtype = "No Wounds?"
-            wdescription = "The Number of wounds specified was less than one...why are you consulting this chart?"
-        else:
-            wtype = "Mortal Wound"
-            wdescription = "Your hero has suffered a life-threatening wound and will not recover without aid. He is Incapacitated and must roll on the Injury Table. He must also make a Vigor roll at the start of each round. If the roll is failed, he passes on. A Healing roll stabilizes the victim but leaves him Incapacitated."
-            itbl = "yes"
-
-        if itbl == "yes":
-            #Determine if a Hit location was specified already
-            if loca.lower() == "h":
-                iroll = 11
-            elif loca.lower() == "g":
-                iroll = 5
-            elif loca.lower() == "ra":
-                iroll = 3
-                aroll = 2
-            elif loca.lower() == "la":
-                iroll = 3
-                aroll = 1
-            elif loca.lower() == "rl":
-                iroll = 10
-                lroll = 2
-            elif loca.lower() == "ll":
-                iroll = 10
-                lroll = 1
-            elif loca.lower() == "c":
-                iroll = 2
-            else:  #none of the above were provided...wo will need to determine randomly
-                iroll = randint(2,12)
-            #resolve the injury table stuff...
-            if iroll == 2:
-                iloc = "Unmentionables"
-                idescription = "The hero suffers an embarrassing and painful wound to the groin."
-            elif iroll == 3 or iroll == 4:
-                if loca != "ra" and loca != "la":  #  If a hit location was not specified (or not recognized) already, determine randomly
-                    aroll = randint(1,2)
-                if aroll == 1:
-                    warm = "Left"
-                else:
-                    warm = "Right"
-                iloc = warm + " Arm"
-                idescription = "The arm is rendered useless."
-            elif iroll >= 5 and iroll <= 9:  #will need to make another random roll
-                iloc = "Guts"
-                idescription = "Your hero catches one somewhere between the crotch and the chin."
-                groll = randint(1,6)
-                if groll == 1 or groll == 2:
-                    #idescription += " <b>Broken (" + str(groll) + ")</b> His Agility is reduced by a die type (min dr)."
-                    idescription += " <b>Broken (" + str(groll) + ")</b> His Agility is reduced by a die type (min d4)."
-                elif groll == 3 or groll == 4:
-                    idescription += " <b>Battered (" + str(groll) + ")</b> His Vigor is reduced by a die type (min d4)."
-                else:
-                    idescription += " <b>Busted (" + str(groll) + ")</b> His Strength is reduced by a die type (min d4)."
-            elif iroll == 10:
-                if loca != "ll" and loca != "rl":  #  If a hit location was not specified (or not recognized) already, determine randomly
-                    lroll = randint(1,2)
-                if lroll == 1:
-                    wleg = "Left"
-                else:
-                    wleg = "Right"
-                iloc = wleg + " Leg"
-                idescription = "The character's leg is crushed, broken, or mangled. His Pace is reduced by 1."
-            else:  #Will need to make another random roll for this one.
-                iloc = "Head"
-                idescription = "Your hero has suffered a grievous injury to his head."
-                hroll = randint(1,6)  #determine how the head is impacted by the wound
-                if hroll == 1 or hroll ==2:
-                    idescription += "<b>Hideous Scar (" + str(hroll) + ")</b>Your hero now has the Ugly Hindrance."
-                elif hroll == 3 or hroll == 4:
-                    idescription += "<b>Blinded (" + str(hroll) + ")</b> One or both of your hero's eyes was damaged. He gains the Bad Eyes Hindrance."
-                else:
-                    idescription += "<b>Brain Damage (" + str(hroll) + ")</b> Your hero suffers massive trauma to the head. His Smarts is reduced one die type (min d4)."
-            idescription += " Make a Vigor roll applying any wound modifiers. If the Vigor roll is failed, the injury is permanent regardless of healing. If the roll is successful, the effect goes away when all wounds are healed."
-            if iroll == 2:
-                idescription +=" If the injury is permanent, reproduction is out of the question without miracle surgery or magic."
-            if loca != "h" and loca != "g" and loca != "c" and loca != "rl" and loca != "ll" and loca != "ra" and loca != "la":
-                idescription +="<br><br><b>***If the attack that caused the Injury was directed at a specific body part, use that location instead of rolling randomly.***</b>"
-            myStr = "[" + wtype + "] ==>" + wdescription + "<br><br><b>Injury Table Result ("+ str(iroll) +"): </b> [" + iloc + "] ==> " + idescription
-        else:
-            myStr = "[" + wtype + "] ==>" + wdescription
-        return myStr
-
-class ract(std):
-    #----------------------The Reaction Table
-    #  This is used to randomly determine the general mood of NPCs toward the player characters.  This simulates a 2d6 roll
-    #  and displays the reaction.  This roll can be modified by the Charisma of the player(s).
-    #  Usage:  [ract()] - No Charisma modifier
-    #          [ract(2)] - A +2 Charisma modifier
-    #          [ract(-2)] - A -2 Charisma modifier
-    #----------------------
-    global charisma
-    
-    def __init__(self,chmod=0):
-        global charisma
-        std.__init__(self)
-        charisma = chmod
-
-    
-    def __str__(self):
-        global charisma
-        r1roll = randint(2,12)
-        rroll = r1roll + charisma
-        if rroll == 2:
-            reaction = "Hostile"
-            rdescription = "The NPC is openly hostile and does his best to stand in the hero's way. He won't help without an overwhelming reward or payment of some kind."
-        elif rroll >=3 and rroll <=4:
-            reaction = "Unfriendly"
-            rdescription = "The NPC is openly hostile and does his best to stand in the hero's way. He won't help without an overwhelming reward or payment of some kind."
-        elif rroll >=5 and rroll <=9:
-            reaction = "Neutral"
-            rdescription = "The NPC has no particular attitude, and will help for little reward if the task at hand is very easy. If the task is difficult, he'll require substantial payment of some kind."
-        elif rroll >=10 and rroll <=11:
-            reaction = "Friendly"
-            rdescription = "The NPC will go out of his way for the hero. He'll likely do easy tasks for free (or very little), and is willing to do more dangerous tasks for fair pay or other favors."
-        else:
-            reaction = "Helpful"
-            rdescription = "The NPC is anxious to help the hero, and will probably do so for little or no pay depending on the nature of the task."
-        #myStr = "[" + reaction + "(" + str(r1roll) + "+Charisma Mods("+str(charisma)+")="+str(rroll)+")] ==> " + rdescription
-        myStr = "["+str(r1roll)+"+"+str(charisma)+"(charisma modifier)="+str(rroll)+"] ==> "+reaction+":  "+rdescription
-        return myStr
-
-class ooc(std):
-    #--------------------The Out of Control Vehicle Table
-    #  This table is used when a vehicle is injured during combat and must determine what happens to the vehicle.  This is a 2d6
-    #  roll and displays the results of the roll.  This will also display altitude information for flying vehicles.
-    #  Usage:  [ooc()]
-    #--------------------
-    
-    def __init__(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        ooroll = randint(2,12)
-        oodescripton = "Something"
-        if ooroll == 2:
-            ooeffect = "Roll Over"
-            rroll = randint(1,6)
-            oodescription = "The vehicle performs a Slip and rolls over "+ str(rroll)+ " time"
-            if rroll < 2:
-                oodescription +="s"
-            oodescription += " in that direction. Roll collision damage for the vehicle and everyone inside. Any exterior-mounted weapons or accessories are ruined."
-        elif ooroll == 3 or ooroll == 4:
-            ooeffect = "Spin"
-            sroll = randint(1,6)
-            froll = randint(1,12)
-            oodescription = "Move the vehicle "+str(sroll)+"\" in the direction of the maneuver, or "+str(sroll)+"\" away from a damaging blow. At the end of the Spin,the vehicle is facing is "+str(froll)+" o'clock."
-        elif ooroll >= 5 and ooroll <= 9:
-            ooeffect = "Skid"
-            sroll = randint(1,4)
-            oodescription = "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
-        elif ooroll == 10 or ooroll == 11:
-            ooeffect = "Slip"
-            sroll = randint(1,6)
-            oodescription = "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
-        else:
-            ooeffect = "Flip"
-            froll = randint(1,4)
-            oodescription = "The vehicle flips end over end "+str(froll)+" times. Move it forward that many increments of its own length. Roll collision damage for the vehicle, its passengers, and anything it hits. "
-            shroll = randint(1,2)
-            if shroll == 1:
-                oodescription += "<br><br><b>Note:</b> If the vehicle is slow and/or heavy (such as a tank) it Slips instead: "
-                sroll = randint(1,6)
-                oodescription += "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
-            else:
-                oodescription += "<br><br><b>Note (GM's discretion):</b> If the vehicle is slow and/or heavy (such as a tank) it Skids instead: "
-                sroll = randint(1,4)
-                oodescription += "Move the vehicle "+str(sroll)+"\" left or right (in the direction of a failed maneuver, or away from a damaging attack)."
-
-        oodescription += "<br><br>For flying vehicles conducting combat in the air, the vehicle"
-        altchange = randint(2,12)
-        if altchange == 2:
-            dwn = randint(2,20)
-            oodescription += " loses "+str(dwn)+"\" of altitude."
-        elif altchange == 3 or altchange == 4:
-            dwn = randint(1,10)
-            oodescription += " loses "+str(dwn)+"\" of altitude."
-        elif altchange >= 5 and altchange <= 9:
-            oodescription += " has no change in altitude."
-        else:
-            altup = randint(1,10)
-            oodescription += " gains "+str(altup)+"\" of altitude."
-        myStr = "[" + ooeffect + "(" + str(ooroll) + ")] ==> " + oodescription
-        return myStr
-
-class vcrit(std):
-    #----------------The Critical Hit Vehicle Table
-    #  This table generates a 2d6 roll to determine the Critical Hit results every time a vehicle takes a wound.  There are no
-    #  modifiers to this roll
-    #  Usage [vcrit()]
-    #----------------
-    
-    def __init__(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        chitroll = randint(2,12)
-        if chitroll == 2:
-            cheffect = "Scratch and Dent"
-            chdescription = "The attack merely scratches the paint. There's no permanent damage."
-        elif chitroll == 3:
-            cheffect = "Engine"
-            chdescription = "The engine is hit. Oil leaks, pistons misfire, etc. Acceleration is halved (round down). This does not affect deceleration, however."
-        elif chitroll == 4:
-            cheffect = "Locomotion"
-            chdescription = "The wheels, tracks, or whatever have been hit. Halve the vehicle's Top Speed immediately. If the vehicle is pulled by animals, the shot hits one of them instead."
-        elif chitroll == 5:  #Need to make an additional roll to see what direction the vehicle can turn...
-            cheffect = "Controls"
-            troll = randint(1,2)
-            if troll == 1:
-                aturn = "left"
-            else:
-                aturn = "right"
-            chdescription = "The control system is hit. Until a Repair roll is made, the vehicle can only perform turns to the "+str(aturn)+". This may prohibit certain maneuvers as well."
-        elif chitroll >= 6 and chitroll <=8:
-            cheffect = "Chassis"
-            chdescription = "The vehicle suffers a hit in the body with no special effects."
-        elif chitroll == 9 or chitroll == 10:
-            cheffect = "Crew"
-            chdescription = "A random crew member is hit. The damage from the attack is rerolled. If the character is inside the vehicle, subtract the vehicle's Armor from the damage. Damage caused by an explosion affects all passengers in the vehicle."
-        elif chitroll == 11:
-            cheffect = "Weapon"
-            chdescription = "A random weapon on the side of the vehicle that was hit is destroyed and may no longer be used. If there is no weapon, this is a Chassis hit instead (The vehicle suffers a hit in the body with no special effects)."
-        else:
-            cheffect = "Wrecked"
-            chdescription = "The vehicle is wrecked and automatically goes Out of Control.<br><br><b>[Out of Control]</b> ==>"+str(ooc())
-        myStr = "["+cheffect+" ("+str(chitroll)+")] ==> "+chdescription
-        return myStr
-
-    def ooc(self):
-        return vcritooc(self)
-
-class swdhelps(std):
-    #Display help information for this die roller - it will list all the available commands, and how to use them
-    
-    def __init__(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        myStr = "<table border='1' valign='top'>\
-        <tr>\
-            <td colspan='3'>This chart will show you the various commands you can use and what is required, etc.  The <i><b>italicized text</b></i> are optional variables.  Any text that is not italicized and is within parentheses is required.  About the only roll that has a required element is the Knockout Blow roll (kob).</td>\
-        </tr>\
-        <tr>\
-            <td align='center'><b>Die Command</b></td><td align='center' width='55%'><b>Description</b></td><td align='center'width='30%'><b>Example</b></td>\
-        </tr>\
-        <tr>\
-            <td><b>[fright(<i>monster's fear modifier</i>)]</b></td><td>Rolls on the <b>Fright Table</b>.  This command generates a number between 1 and 20 and displays the corresponding entry from the Fright Table.</td><td>[fright()]<br>[fright(6)]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[kob(#ofWounds,<i>hitLocation</i>)]</b></td><td>Rolls on the <b>Knockout Blow Table</b> as well as the <b>Injury Table</b> if necessary.  The number of wounds must be specified, however, the location only needs to be specified if a particular body part was targeted.  If a hit location was targeted, then the following codes should be used:<br>\
-                <ul>\
-                    <li>h = head</li>\
-                    <li>g = guts/other vital areas</li>\
-                    <li>c = crotch/groin</li>\
-                    <li>la = left arm</li>\
-                    <li>ra = right arm</li>\
-                    <li>ll = left leg</li>\
-                    <li>rl = right leg</li>\
-                </ul><br>If no hit location is specified, the hit location will be determined when the roll on the Injury Table is necessary.  When specifiying a hit locations, the code must be entered within double quotes.</td><td><b>3 wounds, no called shot</b><br>[kob(3)]<br><b>2 wounds to the head</b><br>[kob(2,\"h\")]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[ract(<i>Charisma Mods</i>)]</b></td><td>Rolls on the <b>Reaction Table</b>.  Will generate the initial reaction to the PCs.  If the Charisma modifiers are supplied, they will be taken into account as well.  Remember that this table is generally only consulted when the reaction of the NPC is comlpetely unknown to the GM.</td><td><b>Reaction no Charisma Mods</b><br>[ract()]<br><b>Reaction with +2 Charisma Mods</b><br>[ract(2)]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[vcrit()]</b></td><td>Rolls on the <b>Critical Hit Table</b> for vehicles.  If a roll on the Out of Control Chart is necessary, it will automatically roll on that table as well.</td><td>[vcrit()]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[ooc()]</b></td><td>Rolls on the <b>Out of Controll Table</b> for vehicles.  This roll will automatically determine any directions/movement rolls as well.</td><td>[ooc()]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[fortune()]</b></td><td>Rolls on the <b>Fortune Table</b> for the Showdown Skirmish rules.  This roll will automatically roll on the <b>Freak Event Table</b> if necessary</td><td>[fortune()]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[freak()]</b></td><td>Rolls on the <b>Freak Event Table</b>.</td><td>[freak()]</td>\
-        </tr>\
-        <tr>\
-            <td><b>[swdhelps()]</b></td><td>Displays this help list.</td><td>[swdhelps()]</td>\
-        </tr>\
-        </table>"
-        return myStr
-
-class fortune(std):
-    
-    def __init___(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        forroll = randint(2,12)
-        if forroll == 2 or forroll == 12: #Need to roll on Freak Event Table
-            fortune = "Freak Event!"
-            fdescription = "Roll on the Freak Event Table.<br><br><b>[Freak Event Table]</b> ==> "+str(freak())
-        elif forroll == 3:
-            fortune = "Twist of Fate"
-            fdescription = "Take a benny from your opponent. If he does not have one, he must immediately remove any one Extra from play."
-        elif forroll == 4:
-            fortune = "The Quick and the Dead"
-            fdescription = "Swap one of your opponent's cards for any one of yours."
-        elif forroll == 5:
-            fortune = "Rally"
-            fdescription = "Pick any one unit on the board with Shaken figures. All those figures recover automatically."
-        elif forroll >= 6 and forroll <= 8:
-            fortune = "Hand of Fate"
-            fdescription = "Gain one extra benny."
-        elif forroll == 9:
-            fortune = "Close Call"
-            fdescription = "Any one of your opponent's units stumbles, becomes confused, or is otherwise disrupted. All its members suffer -2 to their trait rolls this round."
-        elif forroll == 10:
-            fortune = "Teamwork"
-            fdescription = "Pick any one other unit within 12\" of this one. Discard its Action Card. It acts on the Joker along with this unit, and gains the usual bonuses as well."
-        else:
-            fortune = "Out of Ammo"
-            fdescription = "Pick any one enemy unit. It's out of ammo or Power Points (your choice). If this result cannot be applied, you gain a benny instead."
-        myStr = "["+fortune+" ("+str(forroll)+")] ==>"+fdescription
-        return myStr
-
-    
-    def freak(self):
-        return fortunefreak(self)
-
-class freak(std):
-    
-    def __init__(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        feroll = randint(1,10)
-        if feroll == 1:
-            fevent = "Storm"
-            fedescription = "A sudden storm rolls in. Rain begins to pour and visibility is limited to 12\". All attack rolls are at -1, and black powder weapons don't work at all. The round after this event, all streams become impassable, even at fords. Only bridges remain."
-        elif feroll == 2:
-            fevent = "Fire!"
-            fedescription = "Fire breaks out on the board! Roll randomly among each occupied building, patch of trees, or other flammable terrain type. If none of these are occupied, roll randomly among all flammable terrain pieces. The entire building or forest catches fire this round and causes 2d6 damage to everything within. The fire continues for the rest of the game--unless a storm comes, which quenches it immediately.<br><br>At the beginning of each turn thereafter, roll 1d6 for each flammable structure within 4\" (adjacent buildings, another patch of forest, etc.). On a 4-6, that structure catches fire as well. Check to see if these new fires spread in the following rounds."
-        elif feroll == 3:
-            fevent = "Blood Ties"
-            fedescription = "One of the Wild Cards on the other side is related or has some other special bond with one of your heroes (a Wild Card of your choice). For the rest of the battle, these two won't attack each other directly unless there are no other targets on the board."
-        elif feroll == 4:
-            fevent = "Death of a Hero"
-            inspireroll = randint(1,2)
-            if inspireroll == 1:
-                fedescription ="The next time one of your Wild Cards dies, his noble sacrifice triggers new resolve in his companions.  When your next Wild Card is Incapacitated the rest of your force is inspired by his legacy and adds +1 to all their rolls until another of your Wild Cards is killed."
-            else:
-                fedescription = "The next time one of your Wild Cards dies, his noble sacrifice triggers bone-chilling dread in his companions. When your next Wild Card is Incapacitated the rest of your force is filled with dread. They subtract -1 from all their rolls for the rest of the game until an <i>enemy</i> Wild Card is slain."
-        elif feroll == 5:
-            fevent = "Fickle Fate"
-            fedescription = "Fate favors the underdog. The side with the fewest bennies draws until it has the same number as their foe. Place these in the common pool."
-        elif feroll == 6:
-            fevent = "Back from the Dead"
-            fedescription = "One of your dead was just knocked unconscious. He returns in the spot where he fell. If this is a Wild Card, he returns with but a single wound."
-        elif feroll == 7:
-            fevent = "Bitter Cold/Heat"
-            fedescription = "The weather heats up or cools down, depending on your environment. All troops become tired or bogged down and reduce their running rolls by half for the rest of the game."
-        elif feroll == 8:
-            fevent = "Battle Tested"
-            fedescription = "Any one of your units improves any one skill or attribute a die type immediately."
-        elif feroll == 9:
-            fevent = "The Fog"
-            fedescription = "Dense fog, mist, or smoke rolls drifts over the battlefield. Place two connected Large Burst Templates at the center of one randomly determined board edge. The fog drifts 2d6\" each round in a random direction (roll a d12 and read it like a clock facing). The fog \"bounces\" if it hits an edge in a random direction (so that it never leaves the field)."
-        else:
-            fevent = "Reinforcements"
-            fedescription = "A group of your most common currently-fielded troop type arrives on the field of battle! Place these troops in your deployment area. They act on the Joker this round and are dealt in normally hereafter."
-        myStr = "["+fevent+"("+str(feroll)+")] ==> "+fedescription
-        return myStr
-
-class rdm(std):  #If I get the time and the inspiration - I may try to incorporate a Random Table roller...  I need to think about this one.
-    
-    def __init__(self):
-        std.__init__(self)
-
-    
-    def __str__(self):
-        return myStr
--- a/orpg/dieroller/shadowrun.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: shadowrun.py
-# Author: Michael Edwards (AKA akoman)
-# Maintainer:
-# Version: 1.0
-#
-# Description: A modified form of the World of Darkness die roller to
-#              conform to ShadowRun rules-sets. Thanks to the ORPG team
-#              for the original die rollers.
-#              Thanks to tdb30_ for letting me think out loud with him.
-#         I take my hint from the HERO dieroller: It creates for wildly variant options
-#         Further, .vs and .open do not work together in any logical way. One method of
-#         chaining them results in a [Bad Dice Format] and the other results in a standard
-#         output from calling .open()
-
-#         vs is a classic 'comparison' method function, with one difference. It uses a
-#           c&p'ed .open(int) from die.py but makes sure that once the target has been exceeded
-#           then it stops rerolling. The overhead from additional boolean checking is probably
-#           greater than the gains from not over-rolling. The behaviour is in-line with
-#           Shadowrun Third Edition which recommends not rolling once you've exceeded the target
-#         open is an override of .open(int) in die.py. The reason is pretty simple. In die.py open
-#           refers to 'open-ended rolling' whereas in Shadowrun it refers to an 'Open Test' where
-#           the objective is to find the highest die total out of rolled dice. This is then generally
-#           used as the target in a 'Success Test' (for which .vs functions)
-from die import *
-
-__version__ = "1.0"
-
-class shadowrun(std):
-    
-    def __init__(self,source=[],target=2):
-        std.__init__(self,source)
-
-    
-    def vs(self,target):
-        return srVs(self, target)
-
-    
-    def open(self):
-        return srOpen(self)
-
-class srVs(std):
-    
-    def __init__(self,source=[], target=2):
-        std.__init__(self, source)
-        # In Shadowrun, not target number may be below 2. All defaults are set to two and any
-        # thing lower is scaled up.
-        if target < 2:
-            self.target = 2
-        else:
-            self.target = target
-        # Shadowrun was built to use the d6 but in the interests of experimentation I have
-        # made the dieroller generic enough to use any die type
-        self.openended(self[0].sides)
-
-    
-    def openended(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if (self.data[i].lastroll() >= num) and (self.data[i] < self.target):
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.openended(num)
-
-    
-    def __sum__(self):
-        s = 0
-        for r in self.data:
-            if r >= self.target:
-                s += 1
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            myStr += "] vs " + str(self.target) + " for a result of (" + str(self.sum()) + ")"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
-
-class srOpen(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        self.openended(self[0].sides)
-
-    
-    def openended(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() == num:
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.openended(num)
-
-    
-    def __sum__(self):
-        s = 0
-        for r in self.data:
-            if r > s:
-                s = r
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            self.takeHighest(1)
-            myStr += "] for a result of (" + str(self.__sum__().__int__()) + ")"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
--- a/orpg/dieroller/sr4.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#   openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: sr4.py
-# Author: Veggiesama, ripped straight from Michael Edwards (AKA akoman)
-# Maintainer:
-# Version: 1.1
-#
-# 1.1: Now with glitch and critical glitch detection!
-# 1.1: Cleaned up some of the output to make it simpler.
-#
-# Description: Modified from the original Shadowrun dieroller by akoman,
-#              but altered to follow the new Shadowrun 4th Ed dice system.
-#
-#              SR4 VS
-#              Typing [Xd6.vs(Y)] will roll X dice, checking each die
-#              roll against the MIN_TARGET_NUMBER (default: 5). If it
-#              meets or beats it, it counts as a hit. If the total hits
-#              meet or beat the Y value (threshold), there's a success.
-#
-#              SR4 EDGE VS
-#              Identical to the above function, except it looks like
-#              [Xd6.edge(Y)] and follows the "Rule of Six". That rule
-#              states any roll of 6 is counted as a hit and rerolled
-#              with a potential to score more hits. The "Edge" bonus
-#              dice must be included into X.
-#
-#              SR4 INIT
-#              Typing [Xd6.init(Y)] will roll X dice, checking each
-#              die for a hit. All hits are added to Y (the init attrib
-#              of the player), to give an Init Score for the combat.
-#
-#              SR4 EDGE INIT
-#              Typing [Xd6.initedge(Y)] or [Xd6.edgeinit(Y)] will do
-#              as above, except adding the possibility of Edge dice.
-#
-#              Note about non-traditional uses:
-#              - D6's are not required. This script will work with any
-#                die possible, and the "Rule of Six" will only trigger
-#                on the highest die roll possible. Not throughly tested.
-#              - If you want to alter the minimum target number (ex.
-#                score a hit on a 4, 5, or 6), scroll down and change
-#                the global value MIN_TARGET_NUMBER to your liking.
-
-from die import *
-
-__version__ = "1.1"
-
-MIN_TARGET_NUMBER = 5
-GLITCH_NUMBER = 1
-
-class sr4(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        self.threshold = None
-        self.init_attrib = None
-
-    
-    def vs(self,threshold=0):
-        return sr4vs(self, threshold)
-
-    
-    def edge(self,threshold=0):
-        return sr4vs(self, threshold, 1)
-
-    
-    def init(self,init_attrib=0):
-        return sr4init(self, init_attrib)
-
-    
-    def initedge(self,init_attrib=0):
-        return sr4init(self, init_attrib, 1)
-    
-    def edgeinit(self,init_attrib=0):
-        return sr4init(self, init_attrib, 1)
-
-    
-    def countEdge(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if (self.data[i].lastroll() >= num):
-               # counts every rerolled 6 as a hit
-               self.hits += 1
-               self.data[i].extraroll()
-               self.total += 1
-               done = 0
-            elif (self.data[i].lastroll() <= GLITCH_NUMBER):
-                self.ones += 1
-            self.total += 1
-        if done:
-            return self
-        else:
-            return self.countEdge(num)
-
-    
-    def countHits(self,num):
-        for i in range(len(self.data)):
-            if (self.data[i].lastroll() >= MIN_TARGET_NUMBER):
-                # (Rule of Six taken into account in countEdge(), not here)
-                self.hits += 1
-            elif (self.data[i].lastroll() <= GLITCH_NUMBER):
-                self.ones += 1
-            self.total += 1
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            self.hits = 0
-            self.ones = 0
-            self.total = 0
-            for i in range(len(self.data)):
-                if (self.data[i].lastroll() >= MIN_TARGET_NUMBER):
-                    self.hits += 1
-                elif (self.data[i].lastroll() <= GLITCH_NUMBER):
-                    self.ones += 1
-                self.total += 1
-            firstpass = 0
-            myStr = "["
-            for a in self.data[0:]:
-                if firstpass != 0:
-                    myStr += ","
-                firstpass = 1
-                if a >= MIN_TARGET_NUMBER:
-                    myStr += "<B>" + str(a) + "</B>"
-                elif a <= GLITCH_NUMBER:
-                    myStr += "<i>" + str(a) + "</i>"
-                else:
-                    myStr += str(a)
-            myStr += "] " + CheckIfGlitch(self.ones, self.hits, self.total)
-            myStr += "Hits: (" + str(self.hits) + ")"
-        else:
-            myStr = "[] = (0)"
-        return myStr
-
-class sr4init(sr4):
-    
-    def __init__(self,source=[],init_attrib=1,edge=0):
-        std.__init__(self,source)
-        if init_attrib < 2:
-            self.init_attrib = 2
-        else:
-            self.init_attrib = init_attrib
-        self.dicesides = self[0].sides
-        self.hits = 0
-        self.ones = 0
-        self.total = 0
-        if edge:
-            self.countEdge(self.dicesides)
-        self.countHits(self.dicesides)
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            firstpass = 0
-            myStr = "["
-            for a in self.data[0:]:
-                if firstpass != 0:
-                    myStr += ","
-                firstpass = 1
-                if a >= MIN_TARGET_NUMBER:
-                    myStr += "<B>" + str(a) + "</B>"
-                elif a <= GLITCH_NUMBER:
-                    myStr += "<i>" + str(a) + "</i>"
-                else:
-                    myStr += str(a)
-            myStr += "] " + CheckIfGlitch(self.ones, self.hits, self.total)
-            init_score = str(self.init_attrib + self.hits)
-            myStr += "InitScore: " + str(self.init_attrib) + "+"
-            myStr += str(self.hits) + " = (" + init_score + ")"
-        else:
-            myStr = "[] = (0)"
-        return myStr
-
-class sr4vs(sr4):
-    
-    def __init__(self,source=[], threshold=1, edge=0):
-        std.__init__(self, source)
-        if threshold < 0:
-            self.threshold = 0
-        else:
-            self.threshold = threshold
-        self.dicesides = self[0].sides
-        self.hits = 0
-        self.ones = 0
-        self.total = 0
-        if edge:
-            self.countEdge(self.dicesides)
-        self.countHits(self.dicesides)
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            firstpass = 0
-            myStr = "["
-            for a in self.data[0:]:
-                if firstpass != 0:
-                    myStr += ","
-                firstpass = 1
-                if a >= MIN_TARGET_NUMBER:
-                    myStr += "<B>" + str(a) + "</B>"
-                elif a <= GLITCH_NUMBER:
-                    myStr += "<i>" + str(a) + "</i>"
-                else:
-                    myStr += str(a)
-            #myStr += "] Threshold=" + str(self.threshold)
-            myStr += "] vs " + str(self.threshold) + " "
-            myStr += CheckIfGlitch(self.ones, self.hits, self.total)
-            if self.hits >= self.threshold:
-                myStr += "*SUCCESS* "
-            else:
-                myStr += "*FAILURE* "
-            myStr += "Hits: (" + str(self.hits) + ")"
-        else:
-            myStr = "[] = (0)"
-        return myStr
-
-
-def CheckIfGlitch(ones, hits, total_dice):
-    if (ones * 2) >= total_dice:
-        if hits >= 1:
-            return "*GLITCH* "
-        else:
-            return "*CRITICAL GLITCH* "
-    else:
-        return ""
--- a/orpg/dieroller/srex.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: srex.py
-# Original Author: Michael Edwards (AKA akoman)
-# Maintainer:
-# Original Version: 1.0
-#
-# Description: A modified form of the World of Darkness die roller to
-#              conform to ShadowRun rules-sets. Thanks to the ORPG team
-#              for the original die rollers.
-#              Thanks to tdb30_ for letting me think out loud with him.
-#         I take my hint from the HERO dieroller: It creates for wildly variant options
-#         Further, .vs and .open do not work together in any logical way. One method of
-#         chaining them results in a [Bad Dice Format] and the other results in a standard
-#         output from calling .open()
-
-#         vs is a classic 'comparison' method function, with one difference. It uses a
-#           c&p'ed .open(int) from die.py but makes sure that once the target has been exceeded
-#           then it stops rerolling. The overhead from additional boolean checking is probably
-#           greater than the gains from not over-rolling. The behaviour is in-line with
-#           Shadowrun Third Edition which recommends not rolling once you've exceeded the target
-#         open is an override of .open(int) in die.py. The reason is pretty simple. In die.py open
-#           refers to 'open-ended rolling' whereas in Shadowrun it refers to an 'Open Test' where
-#           the objective is to find the highest die total out of rolled dice. This is then generally
-#           used as the target in a 'Success Test' (for which .vs functions)
-
-# Modified by: Darloth
-# Mod Version: 1.1
-# Modified Desc:
-#       I've altered the vs call to make it report successes against every target number (tn)
-#       in a specified (default 3) range, with the original as median.
-#       This reduces rerolling if the TN was calculated incorrectly, and is also very useful
-#       when people are rolling against multiple TNs, which is the case with most area-effect spells.
-#       To aid in picking the specified TN out from the others, it will be in bold.
-#       vswide is a version which can be used with no arguments, or can be used to get a very wide range, by
-#       directly specifying the upper bound (Which is limited to 30)
-
-from die import *
-
-__version__ = "1.1"
-
-class srex(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-    
-    def vs(self,actualtarget=4,tnrange=3):        #reports all tns around specified, max distance of range
-        return srVs(self,actualtarget,(actualtarget-tnrange),(actualtarget+tnrange))
-
-    
-    def vswide(self,actualtarget=4,maxtarget=12):    #wide simply means it reports TNs from 2 to a specified max.
-        return srVs(self,actualtarget,2,maxtarget)
-
-    
-    def open(self):         #unchanged from standard shadowrun open.
-        return srOpen(self)
-
-class srVs(std):
-    
-    def __init__(self,source=[],actualtarget=4,mintn=2,maxtn=12):
-        std.__init__(self, source)
-        if actualtarget > 30:
-            actualtarget = 30
-        if mintn > 30:
-            mintn = 30
-        if maxtn > 30:
-            maxtn = 30
-        # In Shadowrun, not target number may be below 2. Any
-        # thing lower is scaled up.
-        if actualtarget < 2:
-            self.target = 2
-        else:
-            self.target = actualtarget
-        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
-        if actualtarget > maxtn:
-            maxtn = actualtarget
-        #store minimum for later use as well, also in result printing section.
-        if mintn < 2:
-            self.mintn = 2
-        else:
-            self.mintn = mintn
-        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
-
-        # Shadowrun was built to use the d6 but in the interests of experimentation I have
-        # made the dieroller generic enough to use any die type
-        self.openended(self[0].sides)
-
-    
-    def openended(self,num):
-        if num <= 1:
-            self
-        done = 1
-
-        #reroll dice if they hit the highest number, until they are greater than the max TN (recursive)
-        for i in range(len(self.data)):
-            if (self.data[i].lastroll() >= num) and (self.data[i] < self.maxtn):
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.openended(num)
-
-    #count successes, by looping through each die, and checking it against the currently set TN
-    
-    def __sum__(self):
-        s = 0
-        for r in self.data:
-            if r >= self.target:
-                s += 1
-        return s
-
-    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
-    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
-    #easily be lost.
-    
-    def xsum(self,curtarget):
-        s = 0
-        for r in self.data:
-            if r >= curtarget:
-                s += 1
-        return s
-
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            myStr += "] Results: "
-            #cycle through from mintn to maxtn, summing successes for each separate TN
-            for targ in range(self.mintn,self.maxtn+1):
-                if targ == self.target:
-                    myStr += "<b>"
-                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
-                if targ == self.target:
-                    myStr += "</b>"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
-
-class srOpen(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-        self.openended(self[0].sides)
-
-    
-    def openended(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() == num:
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.openended(num)
-
-    
-    def __sum__(self):
-        s = 0
-        for r in self.data:
-            if r > s:
-                s = r
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            self.takeHighest(1)
-            myStr += "] for a result of (" + str(self.__sum__().__int__()) + ")"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
--- a/orpg/dieroller/trinity.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: trinity.py
-# Author: Jacob Matthew, Talisan Creations
-# Maintainer:
-# Version:
-#   $Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $
-#
-# Description: Aeon Trinity die roller
-# Modified from the WoD dieroller "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
-# Targetthr is the Threshhold target
-# for compatibility with Mage die rolls.
-# Threshhold addition by robert t childers
-# Threshhold functionality removed, some tags remain in code.
-from die import *
-
-__version__ = "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
-
-
-class trinity(std):
-    
-    def __init__(self,source=[],target=7,targetthr=0):
-        std.__init__(self,source)
-        self.target = target
-        self.targetthr = targetthr
-
-    
-    def vs(self,target):
-        self.target = target
-        return self
-
-    
-    def thr(self,targetthr):
-        self.targetthr = targetthr
-        return self
-
-    
-    def sum(self):
-        rolls = []
-        s = 0
-        b = 0
-        for a in self.data:
-            rolls.extend(a.gethistory())
-        for r in rolls:
-            if r >= self.target:
-                s += 1
-            elif r == 1:
-                b -= 1
-        if s == 0:
-            return b
-        else:
-            return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            if self.sum() < 0:
-                myStr += "] result of a (" + str(self.sum()) + ") botch"
-            elif self.sum() == 0:
-                myStr += "] result of a failure"
-            else:
-                myStr += "] result of (" + str(self.sum()) + ") success"
-
-
-        return myStr
--- a/orpg/dieroller/utils.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: dieroller/utils.py
-# Author: OpenRPG Team
-# Maintainer:
-# Version:
-#   $Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $
-#
-# Description: Classes to help manage the die roller
-#
-
-__version__ = "$Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $"
-
-from die import *
-from wod import *
-from d20 import *
-from hero import *
-from shadowrun import *
-from sr4 import *
-from hackmaster import *
-from wodex import *
-from srex import *
-from gurps import *
-from runequest import *
-from savage import *
-from trinity import *
-from mythos import *
-import re
-
-rollers = ['std','wod','d20','hero','shadowrun', 'sr4','hackmaster','srex','wodex', 'gurps', 'runequest', 'sw', 'trinity', 'mythos']
-
-class roller_manager:
-    
-    def __init__(self,roller_class="d20"):
-        try: self.setRoller(roller_class)
-        except: self.roller_class = "std"
-
-    
-    def setRoller(self,roller_class):
-        try:
-            rollers.index(roller_class)
-            self.roller_class = roller_class
-        except: raise Exception, "Invalid die roller!"
-
-    
-    def getRoller(self):
-        return self.roller_class
-
-    
-    def listRollers(self):
-        return rollers
-
-    
-    def stdDieToDClass(self,match):
-        s = match.group(0)
-        num_sides = s.split('d')
-        if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = num_sides[1]
-        else: return self.non_stdDieToDClass(s) # Use a non standard converter.
-
-        if sides.strip().upper() == 'F': sides = "'f'"
-        try:
-            if int(num) > 100 or int(sides) > 10000: return None
-        except: pass
-        return "(" + num.strip() + "**" + self.roller_class + "(" + sides.strip() + "))"
-
-
-    def non_stdDieToDClass(self, s):
-        num_sides = s.split('v')
-        if len(num_sides) > 1: 
-            num_sides; num = num_sides[0]; sides = num_sides[1]
-            if self.roller_class == 'stry': sides = '12'; target = num_sides[1]
-            elif self.roller_class == 'wod': sides = '10'; target = num_sides[1]
-            return "("+num.strip()+"**"+self.roller_class+"("+sides.strip()+")).vs("+target+")"
-        num_sides = s.split('k')
-        if len(num_sides) > 1: 
-            num_sides; num = num_sides[0]; sides = '10'; target = num_sides[1]
-            return "("+num.strip()+"**"+self.roller_class+"("+sides.strip()+")).takeHighest("+target+").open(10)"
-
-
-    #  Use this to convert ndm-style (3d6) dice to d_base format
-    
-    def convertTheDieString(self,s):
-        reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+")
-        (result, num_matches) = reg.subn(self.stdDieToDClass, s)
-        if num_matches == 0 or result is None:
-            try:
-                s2 = self.roller_class + "(0)." + s
-                test = eval(s2)
-                return s2
-            except: pass
-        return result
-
-    
-    def proccessRoll(self,s):
-        return str(eval(self.convertTheDieString(s)))
-
-DiceManager = roller_manager
--- a/orpg/dieroller/wod.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: wod.py
-# Author: OpenRPG Dev Team
-# Maintainer:
-# Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
-#
-# Description: WOD die roller
-#
-# Targetthr is the Threshhold target
-# for compatibility with Mage die rolls.
-# Threshhold addition by robert t childers
-from die import *
-
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
-
-
-class wod(std):
-    
-    def __init__(self,source=[],target=0,targetthr=0):
-        std.__init__(self,source)
-        self.target = target
-        self.targetthr = targetthr
-
-    
-    def vs(self,target):
-        self.target = target
-        return self
-
-    
-    def thr(self,targetthr):
-        self.targetthr = targetthr
-        return self
-
-    
-    def sum(self):
-        rolls = []
-        s = 0
-        s1 = self.targetthr
-        botch = 0
-        for a in self.data:
-            rolls.extend(a.gethistory())
-        for r in rolls:
-            if r >= self.target or r == 10:
-                s += 1
-                if s1 >0:
-                    s1 -= 1
-                    s -= 1
-                else:
-                    botch = 1
-            elif r == 1:
-                s -= 1
-            if botch == 1 and s < 0:
-                s = 0
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            if self.sum() < 0:
-                myStr += "] vs " +str(self.target)+" result of a botch"
-            elif self.sum() == 0:
-                myStr += "] vs " +str(self.target)+" result of a failure"
-            else:
-                myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
-
-
-        return myStr
--- a/orpg/dieroller/wodex.py	Thu Dec 03 00:50:11 2009 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +0,0 @@
-## a vs die roller as used by WOD games
-#!/usr/bin/env python
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#       openrpg-dev@lists.sourceforge.net
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: wodex.py
-# Original Author: Darloth
-# Maintainer:
-# Original Version: 1.0
-#
-# Description: A modified form of the World of Darkness die roller to
-#              conform to ShadowRun rules-sets, then modified back to the WoD for
-#              the new WoD system. Thanks to the ORPG team
-#              for the original die rollers.
-#              Much thanks to whoever wrote the original shadowrun roller (akoman I believe)
-
-
-from die import *
-
-__version__ = "$Id: wodex.py,v 1.9 2007/05/06 16:42:55 digitalxero Exp $"
-
-class wodex(std):
-    
-    def __init__(self,source=[]):
-        std.__init__(self,source)
-
-    
-    def vs(self,actualtarget=6):
-        return oldwodVs(self,actualtarget,(6))
-
-    
-    def wod(self,actualtarget=8):
-        return newwodVs(self,actualtarget,(8))
-
-    
-    def exalt(self, actualtarget=7):
-        return exaltVs(self, actualtarget)
-
-    
-    def exaltDmg(self, actualtarget=7):
-        return exaltDmg(self, actualtarget)
-
-    
-    def vswide(self,actualtarget=6,maxtarget=10):    #wide simply means it reports TNs from 2 to a specified max.
-        return oldwodVs(self,actualtarget,2,maxtarget)
-
-class oldwodVs(std):
-    
-    def __init__(self,source=[],actualtarget=6,mintn=2,maxtn=10):
-        std.__init__(self, source)
-        if actualtarget > 10:
-            actualtarget = 10
-        if mintn > 10:
-            mintn = 10
-        if maxtn > 10:
-            maxtn = 10
-        if actualtarget < 2:
-            self.target = 2
-        else:
-            self.target = actualtarget
-        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
-        if actualtarget > maxtn:
-            maxtn = actualtarget
-        if actualtarget < mintn:
-            mintn = actualtarget
-        #store minimum for later use as well, also in result printing section.
-        if mintn < 2:
-            self.mintn = 2
-        else:
-            self.mintn = mintn
-        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
-
-        # WoD etc uses d10 but i've left it so it can roll anything openended
-        # self.openended(self[0].sides)
-
-    #count successes, by looping through each die, and checking it against the currently set TN
-    #1's subtract successes.
-    
-    def __sum__(self):
-        s = 0
-        for r in self.data:
-            if r >= self.target:
-                s += 1
-            elif r == 1:
-                s -= 1
-        return s
-
-    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
-    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
-    #easily be lost. 1s subtract successes from everything.
-    
-    def xsum(self,curtarget):
-        s = 0
-        for r in self.data:
-            if r >= curtarget:
-                s += 1
-            elif r == 1:
-                s -= 1
-        return s
-
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            myStr += "] Results: "
-            #cycle through from mintn to maxtn, summing successes for each separate TN
-            for targ in range(self.mintn,self.maxtn+1):
-                if (targ == self.target):
-                    myStr += "<b>"
-                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
-                if (targ == self.target):
-                    myStr += "</b>"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
-
-class newwodVs(std):
-    
-    def __init__(self,source=[],actualtarget=8,mintn=8,maxtn=8):
-        std.__init__(self, source)
-        if actualtarget > 30:
-            actualtarget = 30
-        if mintn > 10:
-            mintn = 10
-        if maxtn > 10:
-            maxtn = 10
-        if actualtarget < 2:
-            self.target = 2
-        else:
-            self.target = actualtarget
-        #if the target number is higher than max (Mainly for wide rolls) then increase max to tn
-        if actualtarget > maxtn:
-            maxtn = actualtarget
-        if actualtarget < mintn:
-            mintn = actualtarget
-        #store minimum for later use as well, also in result printing section.
-        if mintn < 2:
-            self.mintn = 2
-        else:
-            self.mintn = mintn
-        self.maxtn = maxtn #store for later use in printing results. (Yeah, these comments are now disordered)
-
-        # WoD etc uses d10 but i've left it so it can roll anything openended
-        # self.openended(self[0].sides)
-
-    #a modified sum, but this one takes a target argument, and is there because otherwise it is difficult to loop through
-    #tns counting successes against each one without changing target, which is rather dangerous as the original TN could
-    #easily be lost. 1s subtract successes from original but not re-rolls.
-    
-    def xsum(self,curtarget,subones=1):
-        s = 0
-        done = 1
-        for r in self.data:
-            if r >= curtarget:
-                s += 1
-            elif ((r == 1) and (subones == 1)):
-                s -= 1
-        if r == 10:
-            done = 0
-            subones = 0
-            self.append(di(10))
-        if done == 1:
-            return s
-        else:
-            return self.xsum(0)
-
-    
-    def openended(self,num):
-        if num <= 1:
-            self
-        done = 1
-        for i in range(len(self.data)):
-            if self.data[i].lastroll() == num:
-                self.data[i].extraroll()
-                done = 0
-        if done:
-            return self
-        else:
-            return self.openended(num)
-
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = "[" + str(self.data[0])
-            for a in self.data[1:]:
-                myStr += ","
-                myStr += str(a)
-            myStr += "] Results: "
-            #cycle through from mintn to maxtn, summing successes for each separate TN
-            for targ in range(self.mintn,self.maxtn+1):
-                if (targ == self.target):
-                    myStr += "<b>"
-                myStr += "(" + str(self.xsum(targ)) + "&nbsp;vs&nbsp;" + str(targ) + ") "
-                if (targ == self.target):
-                    myStr += "</b>"
-        else:
-            myStr = "[] = (0)"
-
-        return myStr
-
-class exaltVs(std):
-    
-    def __init__(self, source=[], actualtarget=7):
-        std.__init__(self, source)
-
-        if actualtarget > 10:
-            actualtarget = 10
-
-        if actualtarget < 2:
-            self.target = 2
-        else:
-            self.target = actualtarget
-
-
-    
-    def xsum(self, target):
-        s = 0
-
-        for r in self.data:
-            if r >= target:
-                s += 1
-            if r == 10:
-                s += 1
-
-        return s
-
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = str(self.data)
-            myStr += " Results: "
-
-            succ = self.xsum(self.target)
-            if succ == 0 and 1 in self.data:
-                myStr += 'BOTCH!'
-            elif succ == 0:
-                myStr += str(succ) + " Failure"
-            elif succ == 1:
-                myStr += str(succ) + " Success"
-            else:
-                myStr += str(succ) + " Successes"
-
-            return myStr
-
-class exaltDmg(std):
-    
-    def __init__(self, source=[], actualtarget=7):
-        std.__init__(self, source)
-        if actualtarget > 10:
-            actualtarget = 10
-
-        if actualtarget < 2:
-            self.target = 2
-        else:
-            self.target = actualtarget
-
-    
-    def xsum(self, target):
-        s = 0
-
-        for r in self.data:
-            if r >= target:
-                s += 1
-        return s
-
-    
-    def __str__(self):
-        if len(self.data) > 0:
-            myStr = str(self.data)
-            myStr += " Results: "
-
-            succ = self.xsum(self.target)
-
-            if succ == 0 and 1 in self.data:
-                myStr += 'BOTCH!'
-            elif succ == 0:
-                myStr += str(succ) + " Failure"
-            elif succ == 1:
-                myStr += str(succ) + " Success"
-            else:
-                myStr += str(succ) + " Successes"
-
-            return myStr
--- a/orpg/main.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/main.py	Thu Dec 10 22:30:40 2009 -0600
@@ -49,12 +49,14 @@
 import orpg.mapper.map
 import orpg.mapper.images
 
+import orpg.dieroller.utils
+
 #Update Manager# Un remark if you have Mercurial installed
 import upmana.updatemana
 import upmana.manifest as manifest
 
 from orpg.dirpath import dir_struct
-from orpg.dieroller.utils import DiceManager
+#from orpg.dieroller.utils import DiceManager
 from orpg.tools.settings import settings
 from orpg.tools.validate import validate
 from orpg.tools.passtool import PassTool
@@ -106,7 +108,8 @@
         self.Bind(wx.EVT_TIMER, self.session.update, self.ping_timer)
 
         # create roller manager
-        self.DiceManager = DiceManager(settings.get("dieroller"))
+        self.DiceManager = orpg.dieroller.utils.roller_manager()
+        self.DiceManager.setRoller(settings.get("dieroller"))
         component.add('DiceManager', self.DiceManager)
 
         #create password manager --SD 8/03
--- a/orpg/orpg_version.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/orpg_version.py	Thu Dec 10 22:30:40 2009 -0600
@@ -4,7 +4,7 @@
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
 DISTRO = "Traipse Beta"
 DIS_VER = "Ornery Orc"
-BUILD = "091203-00"
+BUILD = "091210-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/templates/feature.xml	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/templates/feature.xml	Thu Dec 10 22:30:40 2009 -0600
@@ -1,6 +1,275 @@
 <nodehandler class="tabber_handler" icon="help" module="containers" name="Traipse OpenRPG" version="1.0">
-  <nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
-  <nodehandler class="form_handler" frame="409,414,406,127" height="600" icon="wizard1" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Deck" version="1.0" width="400">
+  <nodehandler class="tabber_handler" frame="499,524,156,129" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Quick Help" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">Quick Help:
+
+The referencing system is an update to the Core of how the Game Tree works.  In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further
+
+A.
+Think of the Game Tree has a folder on your hard drive. Each :: inside the reference syntax works just like a system separator (/ or \)
+
+B.
+Root References start at the tree itself. If the node being referenced changes location the reference will be invalid.
+
+C.
+Child References work at the location of the node containing the reference. 
+
+Example: 
+Game Tree
+- Group
+-- Text Node
+--- Group_2
+---- Text Node_2
+
+In the above Tree example you can reference Text Node_2 with a root reference
+
+!@Group::Group_2::Text Node_2@!
+
+or you can use a Child Reference from within Text Node
+
+!!Group_2::Text Node_2!!
+
+D.
+Parent References work with the Tree Map. Currently Parent References work only when called from a node that has been referenced with a Child Reference. 
+
+This is a bug in the system and is created because the Game Tree currently does not contain a Tree Map. So when you Reference a node using a Root Reference it does not pass a Tree Map for the Parent Reference to look at.
+
+Using the above example, you could reference Text Node from Text Node_2 with the syntax: !#Group::Text Node#! .. but only if you referenced Text Node with the Child Reference.
+
+(That last one is hard to understand, I know. )
+
+The reference system is still a bit primitive in it's implementation.  As I was saying it is an advancement to the Core technology of Traipse OpenRPG.
+
+While it is confusing at first, the model is far superior to other tree referencing systems.  Pre 1.8.0, no node could reference a Grid. The referencing system required the reference to be exact and started at the root. Also, the new model is designed to enable freedom of creation and greater control over the Game Tree.
+
+With the Traipse Game Tree GMs are enabled to reference any data from the Game Tree, no matter where it stands. Players can create fewer nodes and use more of the data with fewer nodes.
+
+Developer Note:
+The syntax is the hardest part to understand and I expect to change that in the future. The Core of a more expansive Game Tree model is designed. In Traipse you do not need to give access permissions to a node in order to reference it's entirety, which is what I see with Index and Namespace from OpenRPG Core.
+
+In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location.
+
+This freedom will help with future design and I feel it also frees up the hands of the GM who does not need to Index, un-Index, Namespace, un-Namspace the various creatures he or she may have in a Game Tree.</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Root Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
+Works at the tree level. Must be exact.
+
+&lt;b&gt;Root Reference 1:&lt;/b&gt; !@Reference Examples::Group::Child@!
+&lt;b&gt;Root Reference 2:&lt;/b&gt; !@Reference Examples::Grid::(2,1)@!</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Grid Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Grid Reference&lt;/b&gt;
+Works by looking at the (Row, Column) of a Grid.
+
+&lt;b&gt;Grid Reference 1:&lt;/b&gt; !@Reference Examples::Grid::(1,1)@!
+&lt;b&gt;Grid Reference 2:&lt;/b&gt; !!Grid::(1,1)!!</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Child Reference" version="1.0">
+  <text hide_title="1" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Child Reference&lt;/b&gt;
+Works at the current tree location.
+
+&lt;b&gt;Child Reference 1:&lt;/b&gt; !!Group::Child!!
+&lt;b&gt;Child Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!
+</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Parent Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Parent Reference&lt;/b&gt;
+Works by indexing the map of the node with the Reference.
+Works with a Child Reference only. 
+
+&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Group_3::Child_3!!
+&lt;b&gt;Parent Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!</text>
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples" module="containers" name="Group" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="forms" name="Child" version="1.0">
+  <text multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell size="147">0</cell>
+      <cell>0</cell>
+    </row>
+    <row version="1.0">
+      <cell>!!Group::Child!!</cell>
+      <cell>0</cell>
+    </row>
+  </grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
+  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
+
+This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
+
+What is OpenRPG:
+OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
+
+What is Traipse OpenRPG:
+Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
+
+Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using Chat" version="1.0">
+  <text multiline="1" send_button="0">The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few.
+
+The chat includes a set of commands. You can learn about the commands by entering /help
+
+The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text.</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using The Map" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
+The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
+
+When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
+
+Lurker or in the Lobby: You cannot access any map tab or changes it's settings.
+
+Player: You have access to the Miniatures tab and the Whiteboard tab.
+
+GM: You have access to all of the tabs.
+
+The Layers:
+A small description of each of the layers.
+
+Background: You can set an image as the background, an image as a tile, or you can set a color.
+
+Grid: You can change the grid size, lines, turn off the grid snap, and change the grid shape.
+
+Miniatures: You can add new or remove miniatures and change mini properties and labels.
+
+Whiteboard: With the whiteboard you can draw lines or add text to the map.
+
+Fog: The fog layer hides the entire map from the prying eyes of players.
</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
+
+Grid Nodes:
+  Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@!
+The example will return the top left most cell data. The grid understands coordinates like this (Row, Column)
+
+  Grid nodes can reference node data just like any other node can.  With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll.  While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. 
+
+  Here is an example with a 3 x 3 Grid
+Example: !@Grid::([#1d3], [#1d3])@!
+
+The result will be a random event from the grid.
+
+Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52)
+
+List Nodes:
+  List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node.
+
+  For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references.
+
+(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.)
+
+  Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!!
+
+Text Nodes:
+  Text nodes remain little changed.  I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes.
+
+  Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes.
+
+  Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
+
+Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
+
+(Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map)
+
+Reference Types:
+  There are three ways of references node data. A Root Reference, a Child Reference, and a Parent Reference.
+
+Root Reference: 
+  A node reference that starts at the Game Tree. The location of the node must be exact or you will return an Invalid Reference!
+
+A Root Reference uses this syntax:
+!@Node::Child::Data@!
+
+Child Reference: 
+  A node reference syntax that starts by looking at within the current container node. As long as the Child Reference is in the same container as the node, the container can change location and the reference will not be damaged. Child References work from within a PC Sheet node as well.
+
+A Child Reference uses this syntax:
+!!Node::Child::Data!!
+
+Parent Reference:
+  A node reference syntax that starts by looking at the tree map and the reference used, then makes an addendum to the node's map to create a reference.  The Parent Node is used when you want to reference the data in a node that is within a different container. Currently Parent References only work if they are used as a reference within a node.
+
+A Parent Reference uses this syntax:
+!#Node::Child::Data#!
+
+Syntax for Special PC Sheet Nodes:
+  The nodes for the specialized PC Sheets now have a new syntax.
+
+Skills, Saves, and Abilities:
+  Skills, Saves, and Abilities all have a similar referencing syntax.  You can return the base value of each by using the correct syntax.
+
+Examples:
+!@Jonethan::Skill::Jump@! (Returns Jump ranks)
+!@Mikael::Strength@! (Returns Ability Score and Mod)
+!@Draj::Will@! (Returns Will Save and Mod)
+
+(Saves and Abilities have a short hand and a long hand. Abilities can use the three letter abbreviation, while saves short hand are Fort, Ref, and Will)
+
+  You can append Check to check each of these against a 1d20 roll, or you can append Mod to discover the Modifier. The Mod can be useful in other nodes
+
+Combat:
+  You can now reference your attacks easily with the Game Tree.  Using the Attack syntax you can select modifier type, and a weapon to attack with.
+Example: !@Kammen-Pai::Attack::M::Dagger@!
+
+Modifier Type:
+  There are two modifier types Melee (M) or Ranged (R) You will see I added can use the long word or the short hand.
+
+Powers, Spells and Feats:
+  Power, Spells and Feats are hard to sometimes hard to remember, and even harder to code.  The use of the Power, Spell or Feat syntax serves as an emote of what you are doing, as well as a reminder of what your Power, Spell, or Feat does.
+
+Examples: 
+!@Kammen-Pai::Cast::Ray of Frost@!
+!@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Setting up a Server" version="1.0">
+  <text multiline="1" send_button="0">In Traipse starting a server has never been easier.  The setup is as easy as 1., 2., 3
+
+1. You will need to first start the Server GUI or the basic text based Server at least once so your software creates the server_ini.xml files in your myfiles directory. You can start it once and quit.
+
+2. Edit the server_ini.xml file. Here you can set the server's name, the boot password, and even set the servers port.
+
+Traipse allows you to specify a server port instead of the software demanding port 6774.
+
+3. This is the hardest step. You need to make sure your selected port is forwarded by your router and open to your firewall.
+
+That's it! You can now start the server and register it to the meta for all users to enjoy!</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Adding to the Manual" version="1.0">
+  <text multiline="1" send_button="0">Do you see something that could be explained eaiser?  Report the problem as a bug and it will be added to the manual.</text>
+</nodehandler><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Release Notes" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse" />
+  </nodehandler>
+  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Traipse User Guide" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
+  </nodehandler>
+  </nodehandler><nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
+  <nodehandler class="form_handler" frame="514,464,226,108" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
+  <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
+  <list hide_title="0" raw_mode="1" send_button="1" type="1">
+    <option selected="1" value="">!!Chapter 1::Part 1!!</option>
+    <option selected="0" value="">!!Chapter 1::Part 2!!</option>
+    <option selected="0" value="">!!Chapter 1::Part 3!!</option>
+  </list>
+</nodehandler><nodehandler class="tabber_handler" frame="400,400,392,45" icon="book" map="Traipse OpenRPG::Bonus Nodes::Book" module="containers" name="Chapter 1" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 1" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+&lt;b&gt;Chapter 1 Part 1&lt;/b&gt;
+&lt;br /&gt;&lt;br /&gt;
+An introduction to your adventure module can be placed here.</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,435,110" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 2" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+&lt;b&gt;Chapter 1 Part 2&lt;/b&gt;
+&lt;br /&gt;&lt;br /&gt;
+The adventurers have come this far.</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 3" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+&lt;b&gt;Chapter 1 Part 3&lt;/b&gt;
+&lt;br /&gt;&lt;br /&gt;
+Is this the end already?</text>
+</nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="409,414,422,76" height="600" icon="wizard1" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Deck" version="1.0" width="400">
   <nodehandler class="rpg_grid_handler" frame="400,400,425,69" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Deck" module="rpg_grid" name="52 Card Deck" version="1.0">
   <grid autosize="1" border="1">
     <row version="1.0">
@@ -20,10 +289,9 @@
 </nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,501,72" height="600" icon="orc" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Encounters" version="1.0" width="400">
   <nodehandler class="listbox_handler" frame="400,153,348,150" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="forms" name="Roll" version="1.0">
   <list raw_mode="1" send_button="1" type="1">
-    <option selected="1" value="">!!Chart::([#1d3],1)!!</option>
-    <option selected="0" value="">!!Chart::([#1d2],1)!!</option>
-    <option selected="0" value="">Option Text III</option>
-  </list>
+    <option selected="0" value="">!!Chart::([#1d3],1)!!</option>
+    <option selected="1" value="">!!Chart::([#1d2],2)!!</option>
+    </list>
 </nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,0,48" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="rpg_grid" name="Chart" version="1.0">
   <grid autosize="0" border="1">
     <row version="1.0">
@@ -50,121 +318,28 @@
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 1" version="1.0">
   <text multiline="1" send_button="1">A Wandering Minotaur</text>
 </nodehandler><group_atts border="1" cols="1" />
-</nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Bonus Nodes" module="containers" name="Book" version="1.0">
-  <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
-  <list hide_title="0" raw_mode="1" send_button="1" type="1">
-    <option selected="1" value="">!!Chapter 1::Part 1!!</option>
-    <option selected="0" value="">!!Chapter 1::Part 2!!</option>
-    <option selected="0" value="">!!Chapter 1::Part 3!!</option>
-  </list>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Bonus Nodes::Book" module="containers" name="Chapter 1" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 2" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">Chapter 1 Part 2
-
-The adventurers have come this far.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 3" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">Chapter 1 Part 3
-
-Is this the end already?</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 1" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">Chapter 1 Part 1
-
-An introduction to your adventure module can be placed here.</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0">
-  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Traipse User Guide" version="1.0">
-    <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
-  </nodehandler>
-  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Release Notes" version="1.0">
-    <link href="http://www.assembla.com/wiki/show/traipse" />
-  </nodehandler>
-  <nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The gametree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
-
-(Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the gametree map)
-
-Reference Types:
-  There are two ways of references node data. A Root Reference and a Child Reference.
-
-Root Reference: 
-  A node reference that starts at the gametree. The location of the node must be exact or you will return an Invalid Reference!
-
-A Root Reference uses this syntax:
-!@Node::Child::Data@!
-
-Child Reference: 
-  A node reference syntax that starts by looking at within the current container node. As long as the Child Reference is in the same container as the node, the container can change location and the reference will not be damaged. Child References work from within a PC Sheet node as well.
-
-A Child Reference uses this syntax:
-!!Node::Child::Data!!
-
-Syntax for Special PC Sheet Nodes:
-  The nodes for the specialized PC Sheets now have a new syntax.
-
-Skills, Saves, and Abilities:
-  Skills, Saves, and Abilities all have a similar referencing syntax.  You can return the base value of each by using the correct syntax.
-
-Examples:
-!@Jonethan::Skill::Jump@! (Returns Jump ranks)
-!@Mikael::Strength@! (Returns Ability Score and Mod)
-!@Draj::Will@! (Returns Will Save and Mod)
-
-(Saves and Abilities have a short hand and a long hand. Abilities can use the three letter abbreviation, while saves short hand are Fort, Ref, and Will)
-
-  You can append Check to check each of these against a 1d20 roll, or you can append Mod to discover the Modifier. The Mod can be useful in other nodes
-
-Combat:
-  You can now reference your attacks easily with the gametree.  Using the Attack syntax you can select modifier type, and a weapon to attack with.
-Example: !@Kammen-Pai::Attack::M::Dagger@!
-
-Modifier Type:
-  There are two modifier types Melee (M) or Ranged (R) You will see I added can use the long word or the short hand.
-
-Powers, Spells and Feats:
-  Power, Spells and Feats are hard to sometimes hard to remember, and even harder to code.  The use of the Power, Spell or Feat syntax serves as an emote of what you are doing, as well as a reminder of what your Power, Spell, or Feat does.
-
-Examples: 
-!@Kammen-Pai::Cast::Ray of Frost@!
-!@Kammen-Pai::Feat::Ability Focus@!
-
-</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the gametree using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the gametree referencing model as well as some tips on how to make the gametree work the way it was intended.
-
-Grid Nodes:
-  Grid nodes are now referenceable with the coordinates of the grid. Example: !@Grid::(0,0)@!
-The example will return the top left most cell data. The grid understands coordinates like this (Row, Column)
-
-  Grid nodes can reference node data just like any other node can.  With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll.  While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. 
-
-  Here is an example with a 3 x 3 Grid
-Example: !@Grid::([#1d3-1], [#1d3-1])@!
-
-The result will be a random event from the grid.
-
-Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52)
-
-List Nodes:
-  List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node.
-
-  For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references.
-
-(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.)
-
-  Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!!
-
-Text Nodes:
-  Text nodes remain little changed.  I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes.
-
-  Text nodes can be used in conjuction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes.
-
-  Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
-
-Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><group_atts border="1" cols="1" />
+</nodehandler></nodehandler><group_atts border="1" cols="1" />
 </nodehandler><nodehandler class="file_loader" icon="help" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
     <file name="die_roller_notes.xml" />
   </nodehandler>
   <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
-    <group_atts border="1" cols="1" />
+    <nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Templates" module="containers" name="PC Sheets" version="1.0">
+  <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create 4e PC Sheet" version="1.0">
+        <file name="4e_char_sheet.xml" />
+      </nodehandler><nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3.5 Tool" version="1.0">
+        <file name="dnd3.5.xml" />
+      </nodehandler>
+    <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3rd Edition Character Tool" version="1.0">
+        <file name="dnd3e.xml" />
+      </nodehandler>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New St*r W*rs Character Tool" version="1.0">
+        <file name="StarWars_d20character.xml" />
+      </nodehandler>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New d20 Character Tool" version="1.0">
+        <file name="d20character.xml" />
+      </nodehandler>
+      <group_atts border="1" cols="1" />
+</nodehandler><group_atts border="1" cols="1" />
     <nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
       <group_atts border="1" cols="1" />
       <nodehandler class="file_loader" icon="note" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Text Box" version="1.0">
@@ -200,7 +375,9 @@
     </nodehandler>
     <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
       <group_atts border="1" cols="1" />
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
+      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Die Macro" version="1.0">
+        <file name="die_macro.xml" />
+      </nodehandler><nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
         <file name="macro.xml" />
       </nodehandler>
       <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Miniature Library Tool" version="1.0">
@@ -209,19 +386,7 @@
       <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create remote node loader" version="1.0">
         <file name="urloader.xml" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New d20 Character Tool" version="1.0">
-        <file name="d20character.xml" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New St*r W*rs Character Tool" version="1.0">
-        <file name="StarWars_d20character.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="3rd Edition Character Tool" version="1.0">
-        <file name="dnd3e.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="3.5 Tool" version="1.0">
-        <file name="dnd3.5.xml" />
-      </nodehandler>
-    </nodehandler>
   </nodehandler>
   <nodehandler border="1" class="group_handler" cols="1" icon="browser" map="Traipse OpenRPG" module="containers" name="OpenRPG+ Resources" version="1.0">
     <group_atts border="1" cols="1" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/templates/nodes/4e_char_sheet.xml	Thu Dec 10 22:30:40 2009 -0600
@@ -0,0 +1,101 @@
+<nodehandler class="tabber_handler" frame="400,400,358,183" icon="tabber" map="Group" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet" module="forms" name="Using the 4e Node" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">Because the GPL absorbs material that uses it, even secondary material .. this node is designed to be as generic as possible.
+
+Explinations on how to use will be included.</text></nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Skills" version="1.0">
+        <list raw_mode="1" send_button="1" type="1">
+          <option selected="0" value="0">Climb [1d20+5+!!Abilities::(1,3)!!+(!!General::Level!!/2)]</option>
+          <option selected="1" value="0">Hide [1d20+5+!!Abilities::(2,3)!!+(!!General::Level!!/2)]</option>
+          <option selected="0" value="0">Spot [1d20+5+!!Abilities::(4,3)!!+(!!General::Level!!/2)]</option>
+        </list>
+      </nodehandler>
+      <nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet" module="forms" name="General" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Name" version="1.0">
+  <text multiline="0" send_button="0">text</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Player" version="1.0">
+  <text multiline="0" send_button="0">text</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Race" version="1.0">
+  <text multiline="0" send_button="0">text</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Class" version="1.0">
+  <text multiline="0" send_button="0">text</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Level" version="1.0">
+  <text multiline="0" raw_mode="1" send_button="0">4</text>
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet" module="rpg_grid" name="Abilities" version="1.0">
+        <grid autosize="1" border="1">
+          <row version="1.0">
+            <cell>Str</cell>
+            <cell>8</cell>
+          <cell size="197">(!!Abilities::(1,2)!!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Dex</cell>
+            <cell>8</cell>
+          <cell>(!!Abilities::(2,2)!!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Con</cell>
+            <cell>8</cell>
+          <cell>(!!Abilities::(3,2)!!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Int</cell>
+            <cell>8</cell>
+          <cell>(!!Abilities::(4,2)!!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Wis</cell>
+            <cell>8</cell>
+          <cell>(!!Abilities::(5,2)!!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Cha</cell>
+            <cell>8</cell>
+          <cell>(!!Abilities::(6,2)!!-10)/2</cell></row>
+        </grid>
+        <macros>
+          <macro name="" />
+        </macros>
+      </nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet" module="forms" name="Inventory" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">text</text>
+</nodehandler><nodehandler class="form_handler" frame="400,400,210,87" height="600" icon="form" map="4e PC Sheet" module="forms" name="Combat" version="1.0" width="400">
+  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat" module="containers" name="At Will" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat::At Will" module="containers" name="0" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Combat::At Will::0" module="forms" name="Will Spell" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">!#Combat::Spells::0::Cantrip#!</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Combat::At Will::0" module="forms" name="At Will" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
+&lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat" module="containers" name="Spells" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat::Spells" module="containers" name="0" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,260,70" icon="note" map="4e PC Sheet::Combat::Spells::0" module="forms" name="Cantrip" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="0">/me casts &lt;b&gt;Cantrip:&lt;/b&gt; A great powerful magic has been cast.</text>
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><group_atts border="1" cols="1" />
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Weapon</cell>
+      <cell>Damage</cell>
+    </row>
+    <row version="1.0">
+      <cell>Sword</cell>
+      <cell>d6</cell>
+    </row>
+  <row version="1.0"><cell>Mace</cell><cell>d8</cell></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="listbox_handler" frame="400,400,397,93" icon="gear" map="4e PC Sheet" module="forms" name="At Wills" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option selected="0" value="">!!Combat::At Will::0::At Will!!</option>
+    <option selected="1" value="">!!Combat::At Will::0::Will Spell!!</option>
+    <option selected="0" value="">Option Text III</option>
+  </list>
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Spells" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option selected="1" value="">/me casts &lt;b&gt;Spell:&lt;/b&gt; !!Combat::Spells::0::Cantrip!!</option>
+    <option selected="0" value="">Option Text II</option>
+    <option selected="0" value="">Option Text III</option>
+  </list>
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Attacks" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !!Combat::Weapons::(2,1)!! [1d20+!!Abilities::(1,3)!!] &lt;b&gt;Damage:&lt;/b&gt; [1!!Combat::Weapons::(2,2)!!]</option>
+    <option selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !!Combat::Weapons::(3,1)!! [1d20+!!Abilities::(1,3)!!] &lt;b&gt;Damage:&lt;/b&gt; [1!!Combat::Weapons::(3,2)!!]</option>
+    <option selected="0" value="">Option Text III</option>
+  </list>
+</nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/tools/orpg_settings.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/tools/orpg_settings.py	Thu Dec 10 22:30:40 2009 -0600
@@ -186,7 +186,7 @@
         rm = component.get('DiceManager')
         try:
             rm.setRoller(changes)
-            self.chat.SystemPost('You have changed your die roller to the <b>"' + changes + '"</b> roller.')
+            self.chat.SystemPost('You have changed your die roller to the <b>"' + rm.getRoller.name + '"</b> roller.')
         except:
             rm.setRoller('std')
             self.settings.change('dieroller', 'std')
--- a/orpg/tools/predTextCtrl.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/orpg/tools/predTextCtrl.py	Thu Dec 10 22:30:40 2009 -0600
@@ -379,7 +379,7 @@
 
         begin = 0
         for offset in range(insert - 1):
-            if st[-(offset + 2)] not in string.letters:
+            if st[-(offset + 2)] not in string.ascii_letters:
                 begin = insert - (offset + 1)
                 break
         return st[begin:insert]
@@ -460,7 +460,7 @@
                 #  newSt if it's a letter.  If it's not a letter, (e.g. a comma or
                 #  hyphen) a space is added to newSt in it's place.
                 for ch in st:
-                    if ch not in string.letters:
+                    if ch not in string.ascii_letters:
                         newSt += " "
                     else:
                         newSt += ch
@@ -494,7 +494,7 @@
                 #   Handle any other non-ascii events by calling parent's OnChar()
                 self.parent.OnChar(event)     #Call super.OnChar to get default behavior
                 return
-        elif asciiKey in string.letters:
+        elif asciiKey in string.ascii_letters:
            #  This is the real meat and potatoes of predTextCtrl.  This is where most of the
            #  wx.TextCtrl logic is changed.
             (startSel,endSel) = self.GetSelection()                 #  get the curren selection
@@ -511,7 +511,7 @@
             insert = startSel + 1                                   #  creates an int that denotes where the new InsertionPoint
                                                                     #  should be.
             curWord = ""                                            #  Assume there's a problem with finding the curWord
-            if (len(back) == 0) or (back[0] not in string.letters): #  We should only insert a prediction if we are typing
+            if (len(back) == 0) or (back[0] not in string.ascii_letters): #  We should only insert a prediction if we are typing
                                                                     #  at the end of a word, not in the middle.  There are
                                                                     #  three cases: we are typing at the end of the string or
                                                                     #  we are typing in the middle of the string and the next
--- a/plugins/xxheroinit.py	Thu Dec 03 00:50:11 2009 -0600
+++ b/plugins/xxheroinit.py	Thu Dec 10 22:30:40 2009 -0600
@@ -11,13 +11,12 @@
 
         # The Following code should be edited to contain the proper information
         self.name = 'Hero Turn Tool'
-        self.author = 'Heroman, based on xxxinit.py'
-        self.help = """This is the Hero Games turn turn. It is a bit more complex than other games."""
+        self.author = 'Heroman, based on xxxinit.py\n'
+        self.author = 'debugged for Traipse by Prof. Ebral'
+        self.help = """This is the Hero Games turn tool. It is a bit more complex than other games."""
 
 
     def plugin_enabled(self):
-        #You can add new /commands like
-        # self.plugin_addcommand(cmd, function, helptext)
         self.plugin_addcommand('/hinit', self.on_hinit, '- Toggle Init Recording on or off')
         self.plugin_addcommand('/hhelp', self.on_hhelp, '- List all of the Hero Init Commands')
         self.plugin_addcommand('/hstart', self.on_hstart, '- Start the Hero Init Tool', False)
@@ -51,36 +50,35 @@
         self.backup_list = []
         self.dexterity = 99
         self.segment = 12
-        self.state_strings = ["0 Phase","1/2 Phase","Full Phase","Stunned","Not Gone", "Held Full", "Held Half", "Abort"]
+        self.state_strings = ["0 Phase",
+                            "1/2 Phase",
+                            "Full Phase",
+                            "Stunned",
+                            "Not Gone", 
+                            "Held Full", "Held Half", "Abort"]
 
     def plugin_disabled(self):
-        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
-        #such as closing windows created by the plugin
-        self.plugin_removecmd('/test')
-        self.plugin_removecmd('/example')
+        self.plugin_removecmd('/hinit')
+        self.plugin_removecmd('/hhelp')
+        self.plugin_removecmd('/hstart')
+        self.plugin_removecmd('/hact')
+        self.plugin_removecmd('/hseg')
+        self.plugin_removecmd('/hdex')
+        self.plugin_removecmd('/hclear')
+        self.plugin_removecmd('/hadd')
+        self.plugin_removecmd('/hdel')
+        self.plugin_removecmd('/hown')
+        self.plugin_removecmd('/hlist')
+        self.plugin_removecmd('/hsort')
+        self.plugin_removecmd('/hrun')
+        self.plugin_removecmd('/hchange')
+        self.plugin_removecmd('/hset')
+        self.plugin_removecmd('/hchange')
 
-        #This is the command to delete a message handler
-        self.plugin_delete_msg_handler('xxblank')
-
-        #This is how you should destroy a frame when the plugin is disabled
-        #This same method should be used in close_module as well
-        try:
-            self.frame.Destroy()
-        except:
-            pass
+        try: self.frame.Destroy()
+        except: pass
 
     def plugin_incoming_msg(self, text, type, name, player):
-        #This is called whenever a message from someone else is received, no matter
-        #what type of message it is.
-        #The text variable is the text of the message. If the type is a regular
-        #message, it is already formatted. Otherwise, it's not.
-        #The type variable is an integer which tells you the type: 1=chat, 2=whisper
-        #3=emote, 4=info, and 5=system.
-        #The name variable is the name of the player who sent you the message.
-        #The player variable contains lots of info about the player sending the
-        #message, including name, ID#, and currently-set role.
-        #Uncomment the following line to see the format for the player variable.
-        #print player
 
         if self.toggle:
             if text.lower().find("heroinit") != -1:
@@ -91,11 +89,8 @@
     #Chat Commands
     def on_hinit(self, cmdargs):
         self.toggle = not self.toggle
-
-        if self.toggle:
-            self.chat.SystemPost("Init recording on.  Enter your info")
-        else:
-            self.chat.SystemPost("Init recording off")
+        if self.toggle: self.chat.SystemPost("Init recording on.  Enter your info")
+        else: self.chat.SystemPost("Init recording off")
 
     def on_hhelp(self, cmdargs):
             self.chat.InfoPost("Commands:<br>/hclear : Clears out list<br>" +
@@ -125,14 +120,9 @@
 
     def on_hact(self, cmdargs):
         cmds = cmdargs.split(None)
-
-        if len(cmds) == 1:
-            msg = self.do_action(-1, -1, cmds[0])
-        elif len(cmds) == 2:
-            msg = self.do_action(-1, int(cmds[0]), cmds[1])
-        else:
-            msg = "Error in command. See format with hero init"
-
+        if len(cmds) == 1: msg = self.do_action(-1, -1, cmds[0])
+        elif len(cmds) == 2: msg = self.do_action(-1, int(cmds[0]), cmds[1])
+        else: msg = "Error in command. See format with hero init"
         self.chat.InfoPost(msg)
 
     def on_hseg(self, cmdargs):
@@ -142,8 +132,7 @@
             new_seg = int(cmds[0])
             self.segment = new_seg
             self.call_time()
-        except:
-            self.chat.SystemPost("Invalid format.  correct command is: /hseg SEGMENT#")
+        except: self.chat.SystemPost("Invalid format.  correct command is: /hseg SEGMENT#")
 
     def on_hdex(self, cmdargs):
         cmds = cmdargs.split(None, 3)
@@ -152,8 +141,7 @@
             new_dex = int(cmds[0])
             self.dexterity = new_dex
             self.call_time()
-        except:
-            self.chat.SystemPost("Invalid format.  correct command is: /hdex DEX#")
+        except: self.chat.SystemPost("Invalid format.  correct command is: /hdex DEX#")
 
     def on_hclear(self, cmdargs):
         self.init_list = []
@@ -163,18 +151,20 @@
         self.chat.Post("<hr><font color='#ff0000'>New Initiative</font><br><font color='#0000ff'>Set new Initiatives</font>", True)
 
     def on_hadd(self, cmdargs):
+        print cmdargs
         cmds = cmdargs.split(None, 3)
+        print cmds, len(cmds)
         try:
             if len(cmds) == 3:
-                new_dex = int(txt[0])
-                new_spd = int(txt[1])
+                new_dex = int(cmds[0])
+                new_spd = int(cmds[1])
                 self.init_list.append([new_dex, new_spd, cmds[2], 0, -1])
                 self.backup_list.append([new_dex, new_spd, cmds[2], 0, -1])
                 self.list_inits()
-            else:
-                self.chat.SystemPost("Invalid format.  correct command is: /hadd dex spd description (" + str(len(cmds)) + " arguments give)")
+            else: self.chat.SystemPost("Invalid format.  correct command is: /hadd dex spd description (" + str(len(cmds)) + " arguments give)")
 
-        except:
+        except Exception, e:
+            print e
             self.chat.SystemPost("Invalid format.  correct command is: /hadd dex spd description")
 
     def on_hdel(self, cmdargs):
@@ -205,31 +195,22 @@
         if cmdargs == "high":
             self.init_list.reverse()
             self.backup_list.reverse()
-
         self.list_inits()
 
     def on_hrun(self, cmdargs):
         advance = True
         nextlowest = 0
         heldactions = False
-
         for player in self.init_list:
-            if self.actson(player[1]. self.segment):
-                if player[3] == 5 or player[3] == 6:
-                    heltactions = True
+            if self.actson(player[1], self.segment):
+                if player[3] == 5 or player[3] == 6: heltactions = True
                 continue
-
             if player[3] == 1 or player[3] == 2:
                 self.chat.InfoPost("Hero " + player[2] + " needs to act before we advance DEX")
                 advance = False
-
             elif player[3] == 3 or player[3] == 4 or player[3] == 7:
-                if player[0] > nextlowest:
-                    nextlowest = player[0]
-
-            elif player[3] == 5 or player[3] == 6:
-                heltactions = True
-
+                if player[0] > nextlowest: nextlowest = player[0]
+            elif player[3] == 5 or player[3] == 6: heltactions = True
         if not advance:
             return
 
@@ -238,53 +219,40 @@
         if nextlowest == 0 and self.dexterity != 0:
             if heldactions or self.segment == 12:
                 msg = "End of Segment " + str(self.segment) + "."
-                if heldactions:
-                    msg += " There are held actions."
-
+                if heldactions: msg += " There are held actions."
                 msg += "  Issue command again to advance to next segment."
-
                 self.chat.InfoPost(msg)
                 self.dexterity = 0
                 return
-            else:
-                advanceseg = True
-        elif nextlowest == 0 and self.dexterify == 0:
+            else: advanceseg = True
+        elif nextlowest == 0 and self.dexterity == 0:
             advanceseg = True
 
         if advanceseg:
             self.dexterity = nextlowest
             for player in self.init_list:
                 if player[0] == self.dexterity:
-                    if player[3] == 3 or player[3] == 7:
-                        player[3] = 0
-                    elif player[3] == 4:
-                        player[3] = 2
+                    if player[3] == 3 or player[3] == 7: player[3] = 0
+                    elif player[3] == 4: player[3] = 2
         else:
             nextsegment = 0
             while nextsegment == 0:
                 self.segment += 1
-                if self.segment == 13:
-                    self.segment = 1
-
+                if self.segment == 13: self.segment = 1
                 elif self.segment == 12:
                     nextsegment = 12
                     break
 
                 for player in self.init_list:
                     if self.actson(player[1], self.segment):
-                        if player[3] == 0 or player[3] == 3 or player[3] == 7:
-                            nextsegment = self.segment
-
-                    if player[3] == 5 or player[3] == 6:
-                        nextsegment = self.segment
+                        if player[3] == 0 or player[3] == 3 or player[3] == 7: nextsegment = self.segment
+                    if player[3] == 5 or player[3] == 6: nextsegment = self.segment
 
             self.dexterity = self.highestdex()
             for player in self.init_list:
                 heldactions = False
                 if self.actson(player[1], self.segment):
-                    if player[3] != 3 and player[3] != 7:
-                        player[3] = 4
-
+                    if player[3] != 3 and player[3] != 7: player[3] = 4
                     if player[0] == self.dexterity:
                         if player[3] == 3:
                             self.chat.InfoPost(player[2] + " unstuns.")
@@ -292,9 +260,7 @@
                         elif player[3] == 7:
                             self.chat.InfoPost(player[2] + " recovers from the abort")
                             player[3] = 0
-                        else:
-                            player[3] = 2
-
+                        else: player[3] = 2
                     if player[3] == 5 or player[3] == 6 and self.dexterity == 0:
                         self.chat.InfoPost("There are held actions. Issue command again to advance to next segment.")
         self.call_time()
@@ -325,19 +291,16 @@
         msg = ""
         stateindex = 0
         for state in self.state_strings:
-            if stateindex != 0:
-                msg += ", "
+            if stateindex != 0: msg += ", "
             msg += str(stateindex) + "=" + state
             stateindex += 1
         return msg
 
     def is_index(self, value):
         try:
-            if value[:1] == "+":
-                offset = 1
+            if value[:1] == "+": offset = 1
             return True
-        except:
-            return False
+        except: return False
 
     def actson(self, spd, segment):
         speeds=[[0,0,0,0,0,0,0,0,0,0,0,1],
@@ -353,41 +316,30 @@
                 [0,1,1,1,1,1,1,1,1,1,1,1],
                 [1,1,1,1,1,1,1,1,1,1,1,1]]
 
-        if spd < 1 or spd > 12:
-            return False
-
-        if speeds[spd-1][segment-1] == 1:
-            return True
-
+        if spd < 1 or spd > 12: return False
+        if speeds[spd-1][segment-1] == 1: return True
         return False
 
     def highestdex(self):
         dex = 0
         for player in self.init_list:
-            if self.actson(player[1], self.segment) and player[0] > dex:
-                dex = player[0]
+            if self.actson(player[1], self.segment) and player[0] > dex: dex = player[0]
         return dex
 
     def do_action(self, playerid, index, action):
         if index == -1:
             count = 1
             for player in self.init_list:
-                if player[4] == playerid:
-                    index = count
+                if player[4] == playerid: index = count
                 count += 1
-
-        if index == -1:
-            return "You do not have any players in the combat list"
-
+        if index == -1: return "You do not have any players in the combat list"
         index -= 1
         player = self.init_list[index]
-        if playerid != -1 and playerid != player[4]:
-            return "You do not own that player."
+        if playerid != -1 and playerid != player[4]: return "You do not own that player."
 
         # You can only perform a full action if you have a full or held full
         if action == "full":
-            if player[3] != 2 and player[3] != 5:
-                msg = player[2] + " cannot perform a full action."
+            if player[3] != 2 and player[3] != 5: msg = player[2] + " cannot perform a full action."
             else:
                 player[3] = 0
                 msg = player[2] + " performs a full action."
@@ -402,8 +354,7 @@
                     player[3] = 1
                     msg = player[2] + " performs a half action (half remaining)"
         elif action == "hold":
-            if player[3] != 1 and player[3] != 2:
-                msg = player[2] + " cannot hold an action."
+            if player[3] != 1 and player[3] != 2: msg = player[2] + " cannot hold an action."
             else:
                 if player[3] == 2:
                     player[3] = 5
@@ -423,58 +374,45 @@
             elif player[3] == 0 and not self.actson(player[1], self.segment):
                 player[3] = 7
                 msg = player[2] + " aborts!"
-            else:
-                msg = player[2] + " cannot abort yet."
-        else:
-            msg = "Unknown command."
-
+            else: msg = player[2] + " cannot abort yet."
+        else: msg = "Unknown command."
         return msg
 
     def list_inits(self, player=0, send=False):
         msg = "Combat Turn:<br>"
         msg += "<table border=1 cellspacing=1 cellpadding=1><tr><th><th></th></th><th></th><th></th><th></th><th></th><th colspan=12>Segments</th></tr>"
         msg += "<tr><th>#</th><th>Owner</th><th>Name</th><th>Spd</th><th>Dex</th><th>State</th>"
-        for x in xrange(1,13):
-            msg += "<th>" + str(x) + "</th>"
+        for x in xrange(1,13): msg += "<th>" + str(x) + "</th>"
         msg += "</tr>"
         count=1
         for m in self.init_list:
             msg += "<tr><td align=center>"+str(count)+"</td>"
-            if m[4]==-1:
-                msg += "<td><font color=red>GM</font></td>"
-            else:
-                msg += "<td>" + m[4] + "</td>"
+            if m[4]==-1: msg += "<td><font color=red>GM</font></td>"
+            else: msg += "<td>" + m[4] + "</td>"
             msg += "<td><font color='#0000ff'>" + m[2] + "</font></td>"
             msg += "<td align=center><font color='#0000ff'>" + str(m[1]) + "</font></td>"
             msg += "<td align=center><font color='#0000ff'>" + str(m[0]) + "</font></td>"
             msg +="<td>" + self.state_strings[m[3]] + "</td>"
 
             for segment in xrange(1,13):
-                if self.actson(m[1],segment):
-                    msg += "<td align=center>" + str(m[0]) + "</td>"
-                else:
-                    msg += "<td></td>"
+                if self.actson(m[1],segment): msg += "<td align=center>" + str(m[0]) + "</td>"
+                else: msg += "<td></td>"
             msg += "</tr>"
             count += 1
         msg += "</table><br>"
-
-        msg += "It is currently Segment " + str(v.segment) + ", DEX " + str(v.dexterity) + "<br>"
+        msg += "It is currently Segment " + str(self.segment) + ", DEX " + str(self.dexterity) + "<br>"
 
-        if send and player != 0:
-            chat.whisper_to_players(msg, [player])
-        else:
-            self.chat.InfoPost(msg)
+        if send and player != 0: chat.whisper_to_players(msg, [player])
+        else: self.chat.InfoPost(msg)
 
     def call_time(self):
         plist = ""
         msg = "Segment is now " + str(self.segment) + ", DEX " + str(self.dexterity)
         for player in self.init_list:
             if player[3] == 1 or player[3] == 2 or player[3] == 5 or player[3] == 6:
-                if plist != "":
-                    plist += ", "
+                if plist != "": plist += ", "
                 plist += player[2] + "(" + self.state_strings[player[3]] + ")"
-        if plist != "":
-            msg += ": " + plist
+        if plist != "": msg += ": " + plist
         self.chat.Post(msg, True)
 
     def process_user(self, command, player):
@@ -487,11 +425,8 @@
                     self.init_list.append([new_dex, new_spd, txt[3], 0, player[2]])
                     self.backup_list.append([new_dex, new_spd, txt[3], 0, player[2]])
                     msg = "Character " + txt[3] + " added to initiative."
-                else:
-                    msg = "Error in command.  See format with heroinit"
-            except:
-                msg = "Error in command.  See format with heroinit"
-
+                else: msg = "Error in command.  See format with heroinit"
+            except: msg = "Error in command.  See format with heroinit"
             self.chat.whisper_to_players(msg, [player[2]])
 
         elif command == "hact":
@@ -504,14 +439,9 @@
                 index = int(txt[1])
                 action = txt[2]
                 msg = self.do_action(player[2], index, action)
-            else:
-                msg = "Error in command.  See format with heroinit"
-
+            else: msg = "Error in command.  See format with heroinit"
             self.chat.whisper_to_players(msg, [player[2]])
-
-        elif command == "hlist":
-            self.list_inits(player[2], True)
-
+        elif command == "hlist": self.list_inits(player[2], True)
         else:
             msg = "Commands:<br>heroinit (hadd DEX SPEED CHARACTERNAME) : add character CHARACTERNAME with dex DEX and speed SPD to initiative list<br>"
             msg += " Example:  heroinit (hadd 18 4 Joey)<br>"