changeset 243:3bbfd84619c0 beta

Traipse Beta 'OpenRPG' {101018-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 (Closing/Closed) New Features: New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order New to Server GUI, can now clear log New Earthdawn Dieroller New IronClaw roller, sheet, and image Updates: Update to Warhammer PC Sheet. Rollers set as macros. Should work with little maintanence. Update to Browser Server window. Display rooms with ' " & cleaner Update to Server. Handles ' " & cleaner Update to Dieroller. Cleaner, more effecient expression system Update to Hidden Die plugin, allows for non standard dice rolls Fixes: Fix to InterParse that was causing an Infernal Loop with Namespace Internal Fix to XML data, removed old Minidom and switched to Element Tree Fix to Server that was causing eternal attempt to find a Server ID, in Register Rooms thread Fix to metaservers.xml file not being created Fix to Single and Double quotes in Whiteboard text Fix to Background images not showing when using the Image Server Fix to Duplicate chat names appearing Fix to Server GUI's logging output Fix to FNB.COLORFUL_TABS bug Fix to Gametree for XSLT Sheets Fix to Gametree for locating gametree files Fix to Send to Chat from Gametree Fix to Gametree, renaming and remapping operates correctly
author sirebral
date Mon, 18 Oct 2010 23:48:49 -0500
parents 72e0cce81a47
children be04d07341f3
files images/Copyright Notice.txt images/icons.xml images/iron-claw.gif orpg/dieroller/rollers/ironclaw.py orpg/dieroller/utils.py orpg/gametree/gametree.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/core.py orpg/gametree/nodehandlers/d20.py orpg/gametree/nodehandlers/dnd35.py orpg/gametree/nodehandlers/dnd3e.py orpg/gametree/nodehandlers/forms.py orpg/gametree/nodehandlers/minilib.py orpg/gametree/nodehandlers/rpg_grid.py orpg/orpg_version.py orpg/templates/nodes/ironclaw-guide.xml orpg/templates/nodes/ironclaw.xml orpg/tools/InterParse.py
diffstat 18 files changed, 1312 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/images/Copyright Notice.txt	Tue Aug 17 14:53:04 2010 -0500
+++ b/images/Copyright Notice.txt	Mon Oct 18 23:48:49 2010 -0500
@@ -1,3 +1,5 @@
+Ironclaw logo (tm) 1999, 2010 Sanguine Productions. Used with permission from Sanguine Productions Ltd to Knowledge Arcana Mad Mathematics Laboratories, all rights reserved.
+
 The following images are Copyright Sekkyumu and released to the Public Domain
 add.png
 add_button.png
--- a/images/icons.xml	Tue Aug 17 14:53:04 2010 -0500
+++ b/images/icons.xml	Mon Oct 18 23:48:49 2010 -0500
@@ -10,6 +10,7 @@
 <icon name='bullet' file='bullet.gif' />
 <icon name='ccmap' file='ccmap.gif' />
 <icon name='8ball' file='8ball.gif' />
+<icon name='iron-claw' file='iron-claw.gif' />
 <icon name='car' file='car.gif' />
 <icon name='chess' file='chess.gif' />
 <icon name='compass' file='compass.gif' />
Binary file images/iron-claw.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/ironclaw.py	Mon Oct 18 23:48:49 2010 -0500
@@ -0,0 +1,867 @@
+## A die roller as used by IronClaw RPG
+# Copyright (C) 2000-2010 The OpenRPG Project
+#
+#       owner@madmathlabs.com
+#
+# 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: ironclaw.py
+# Author: Prof. Ebral, TaS (Traipse)
+# Maintainer:
+# Version:
+#   $Id: ironclaw.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
+#
+# Description: IronClaw Die Roller
+# Comissioned by Ponderer
+#
+"""
+Notes: The original concept of the Iron Claw roller is too advanced for Ornery Orc so I am taking notes. The idea is a highly desired idea, a PC Sheet that
+can interact with other PC Sheets to expedite die rolls. PC Sheet data will be shared via the map, expected to occur in Pious Paladin, because the map makes
+a safe sand box for the game tree data.
+
+The combat system in Iron Claw is not straight forward enough for compared rolls, so the out put orders the rolls from highest to lowest, coloring the highest
+and the ones. When PC Sheet data can be shared in a safe format, the comparitive possibility already exists. After the makeDecision function the list of dice is returned also, allow for the two dice lists to be rolled and then compared.
+
+By far the most intricate commission I have had so far. I really wish I could have accomplised all that was requested.
+"""
+
+from std import std
+from math import fabs
+import random
+from orpg.dieroller.base import *
+from orpg.tools.InterParse import Parse
+""" For note
+ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
+        sides.strip(), '))']
+s =  ''.join(ret)
+"""
+class ironclaw(std):
+    name = "ironclaw"
+    regGroup = '[a-zA-Z0-9. (::)(\-\+)]+'
+    regExpression = regGroup+'/'+regGroup+'|'+regGroup
+    pcSheets = {}
+    healingTable = {
+    1: ['1d4', '2d4', '2d6', '2d8'],
+    2: ['1d6', '2d6', '2d8', '2d10'],
+    3: ['1d8', '2d8', '2d10', '2d12'],
+    4: ['1d10', '2d10', '2d12', '3d12'],
+    5: ['1d12', '2d12', '3d12', '3d12'],
+    6: ['2d12', '3d12', '3d12', '4d12'],
+    7: ['2d12', '3d12', '4d12', '4d12'],
+    8: ['3d12', '4d12', '4d12', '4d12'],
+    9: ['3d12', '4d12', '5d12', '6d12']
+                }
+    acceptedDice = ['4', '6', '8', '10', '12']
+    deathTable = {
+    6: '1d4', 7: '1d6', 8: '1d8', 9: '1d10', 
+    10: '1d12', 11: '2d12', 12: '3d12', 13: 'Dead'
+                }
+    unconTable = {
+    3: '1d4', 4: '1d6', 5: '1d8', 6: '1d10', 7: '1d12', 
+    8: '2d12', 9: '3d12', 10: '4d12', 11: '4d12', 12: '4d12'
+                }
+    conditions = {'easy': 0, 'medium': 1, 'hard': 2, 'extreme': 3}
+
+    def __init__(self, source=[]):
+        std.__init__(self, source)
+
+    def non_stdDie(self, match):
+        s = match.group(0)
+        vsRoll = s.split('/'); pcSheets = []; PCs = []
+        for roll in vsRoll:
+            PCs.append(roll.split('.'))
+        for pc in PCs:
+            if pc[0].lower() == 'toolbox': return self.ToolBox(pc)
+            else: pcSheets.append(self.findSheets(pc))
+        #
+        actor, aDice, adDice = self.makeDecision(PCs[0], pcSheets[0])
+        myStr = actor; compareTest = None
+        #
+        if len(aDice) > 1: 
+            myStr += ' ' +self.cleanDice(aDice)[0]+ ' => '
+            attackRoll = self.rollDice(aDice)
+            myStr += attackRoll[0]
+            compareTest = self.compareTest(attackRoll[1], [1,1])
+            if compareTest == 'botch': myStr += ' Botch!'
+        if (isinstance(adDice, list)) and (compareTest != 'botch'):
+            myStr += ' Damage: ' +self.cleanDice(adDice)[0]+ ' => '
+            myStr += self.rollDamage(adDice)[0]
+        if len(pcSheets) == 2:
+            if pcSheets[1][0] == True: reactor, rDice, rdDice = self.makeDecision(PCs[1], pcSheets[1][1])
+            else:
+                diceList = ['None']
+                for die in PCs[1]: 
+                    trueDice = self.makeTrueDice(die)
+                    for die in trueDice: diceList.append(die)
+                diceList = self.buildActionList(diceList)
+                rDice = self.diceModifiers(diceList)
+                myStr += ' / ' +str(rDice)+ ' => '
+                rDice.sort(); rDice.reverse()
+                rDiceRolled = self.rollDice(rDice)[0]
+                myStr += str(rDice)
+        return myStr
+
+    def ToolBox(self, commands):
+        ## This is expandable. Aimed for GM use ##
+        if commands[1].lower() == 'clearpcs': 
+            for key in self.pcSheets.keys(): del self.pcSheets[key]
+            return 'Clearing PC Sheets'
+
+    def makeDecision(self, pcAction, pcSheetData):
+        pcSheet = pcSheetData[1]
+        if self.pcSheets.has_key(pcAction[0]): pcNode = pcSheet['Node']
+        else: pcNode = pcSheetData[2]
+        actionList = self.buildActionList(pcAction); skillList = self.buildSkillList(pcSheet['Skills'])
+        ability = self.buildAbilities(pcSheet['Abilities']); nodeList = self.buildNodeList(pcSheet)
+        myStr = '<b>'+self.NameSpaceXI('name', pcSheet['General']).text+ '</b> '
+        diceList = []; options = ['parry', 'guard', 'retreat', 'nocover']
+        toolbox = ['setpc', 'delpc', 'clearpcs', 'update']
+        actions = ['denarii', 'aureals', 'fatigue', 'wounds', 'passout', 
+                    'resolve', 'soak', 'rest', 'block', 'dodge', 'magic', 
+                    'damage', 'meditate', 'initiative', 'strength']
+        #others = ['cast'] ## For future dev
+        #magicCareers = ['cleric', 'elementalist', 'thaumaturge', 'necromancer', 'green and purple mage']
+        damage = None
+        self.updatePC(pcSheet, skillList, ability['speed'], actionList)
+        for action in actionList:
+            action = action.lower(); actionNodes = action.split('::')
+            if action in options: pass ## Pass over these.
+
+            elif action in toolbox:
+                if action == 'setpc': myStr += self.setPCSheet(pcSheetData[2], pcSheet, actionList)
+                elif action == 'delpc': myStr += self.delPCSheet(pcAction[0])
+                elif action == 'update': 
+                    myStr += self.updatePC(pcSheet, skillList, ability['speed'], actionList)
+                    while len(actionList) > 1: actionList.pop()
+
+            elif action in actions:
+                if action in ['denarii', 'aureals']:
+                    myStr += self.setCoin(pcSheet['Purse'], action, actionList)
+                elif action in ['fatigue', 'wounds']:
+                    myStr += self.setWound(pcSheet['Character'], action, ability['body'], actionList)
+                elif action == 'soak':
+                    myStr += 'Soak: '
+                    diceList += self.pcSoak(pcSheet['Defense'])
+                elif action == 'strength':
+                    myStr += 'Strength: '
+                    diceList += self.pcStrength(pcSheet['Abilities'])
+                elif action == 'initiative':
+                    myStr += 'Initiative: '
+                    diceList += self.pcInit(pcSheet['Defense'])
+                elif action in ['block', 'dodge']: 
+                    dice = self.dodgeBlock(action, ability, actionList, pcSheet['Defense'], pcSheet['Equipment'], skillList)
+                    myStr += action.capitalize()+'s'
+                    if dice != 'No Dice Found!': diceList += dice
+                elif action == 'rest':
+                    myStr += self.restPC(pcSheet['Character'], pcSheet['Skills'], ability['body'], action, actionList)
+                elif action == 'meditate':
+                    myStr += self.restPC(pcSheet['Character'], skillList, ability['body'], action, actionList)
+                elif action == 'magic': myStr += self.pcMagic(pcSheet['Character'], actionList)
+                elif action == 'damage': string, damage = self.pcDamage(actionList); myStr += string
+                elif action == 'passout': myStr += self.passoutTest(pcSheet['Character'], pcSheet['Defense'], skillList, ability['will'])
+                elif action == 'resolve':
+                    myStr += 'Resolve: '
+                    diceList += self.pcResolve(pcSheet['Character'], pcSheet['Defense'], skillList, ability['will'])
+
+            elif nodeList.has_key(action):
+                if ability.has_key(action): 
+                    myStr += '<u>Ability; '+action.capitalize()+'</u> '
+                    abilityDice = self.makeTrueDice( str(ability[action].find('text').text) )
+                    for die in abilityDice: 
+                        diceList.append(die)
+                else:
+                    string, dice, damage = self.getNodeValue(action, actionList, ability, nodeList, pcSheet, skillList, pcNode)
+                    myStr += string+' '
+                    if isinstance(dice, list): diceList += dice
+
+            elif skillList.has_key(action):
+                dice = self.getSkillDice(skillList[action])
+                if dice != 'No Dice Found!': diceList += dice
+                myStr += '<u>Skill; '+action.capitalize()+'</u> '
+
+            elif nodeList.has_key(actionNodes[len(actionNodes)-1]):
+                string, dice, damage = self.getNodeValue(action, actionList, ability, nodeList, pcSheet, skillList, pcNode)
+                myStr += string+' '
+                if isinstance(dice, list): diceList += dice
+
+            else:
+                trueDice = self.makeTrueDice(action)
+                for die in trueDice: diceList.append(die)
+        if len(actionList) > 1: diceList.append(actionList[len(actionList)-1])
+        if len(diceList) > 1: diceList = self.diceModifiers(diceList)
+        if damage != None: damage = self.diceModifiers(damage)
+        return myStr, diceList, damage
+
+    def pcMagic(self,  character, actionList):
+        magic = int(actionList[len(actionList)-1])
+        magicPoints = self.NameSpaceVI('magic points', character)
+        cMagic = self.NameSpaceXI('current', magicPoints); cM = int(cMagic.text)
+        mMagic = self.NameSpaceXI('maximum', magicPoints); mM = int(mMagic.text)
+        myStr = 'Regains ' if magic >= 0 else 'Loses '
+        if len(actionList) == 2:
+            if magic < 0:
+                if cM + magic < 0: return 'Insufficient Magic!'
+            cM += magic
+            if cM > mM: cM = mM
+            myStr += str(magic)+ ' Magic.'
+            cMagic.text = str(cM)
+        else:
+            diceList = []
+            for x in xrange(1, len(actionList)): 
+                trueDice = self.makeTrueDice(actionList[x])
+                for die in trueDice:diceList.append(die)
+            diceList.append(actionList[len(actionList)-1])
+            diceList = self.diceModifiers(diceList)
+            while len(actionList) > 1: actionList.pop()
+            addMagic = self.rollDice(diceList); x = 0
+            for m in addMagic[1]: x += int(m)
+            cM += x
+            if cM > mM: cM = mM
+            cMagic.text = str(cM)
+            return 'Regains ' +self.cleanDice(diceList)[0]+ ' => ' +addMagic[0]+ ' => [' +str(x)+ '] Magic.'
+        return myStr
+
+    def pcDamage(self, actionList):
+        if len(actionList) == 2: return 'No Damage Dice', None
+        diceList = []
+        if 'd' in actionList[len(actionList)-1]: mod = '0'
+        else: mod = int(actionList[len(actionList)-1])
+        for x in xrange(1, len(actionList)-1):
+            trueDice = self.makeTrueDice(actionList[x])
+            for die in trueDice: diceList.append(die)
+        diceList.append(mod)
+        while len(actionList) > 1: actionList.pop()
+        return '', diceList
+
+    def pcStrength(self, abilities):
+        strength = self.NameSpaceXI('strength dice', abilities)
+        trueDice = self.makeTrueDice(str(strength.text))
+        return trueDice
+
+    def pcSoak(self, defense):
+        soak = self.NameSpaceXI('soak', defense)
+        trueDice = self.makeTrueDice(str(soak.text))
+        return trueDice
+
+    def pcInit(self, defense):
+        init = self.NameSpaceXI('initiative', defense)
+        trueDice = self.makeTrueDice(str(init.text))
+        return trueDice
+
+    def setCoin(self, purse, action, actionList):
+        denarii = self.NameSpaceXI('denarii', purse); d = int(denarii.text)
+        aureals = self.NameSpaceXI('aureals', purse); a = int(aureals.text)
+        coins = int(actionList[len(actionList)-1])
+        myStr = 'Gains ' if coins >= 0 else 'Loses '
+        if action == 'denarii':
+            d += coins
+            while d >= 24:
+                a += 1; d -= 24
+            myStr += str(coins)+ ' Denarii'
+        if d < 0: a -= 1; d += 24
+        if action == 'aureals':  a += coins; myStr += str(coins)+ ' Aureals'
+        if a < 0: return 'Not enough coins!'
+        if d < 0: return 'Not enough coins!'
+        aureals.text = str(a); denarii.text = str(d)
+        return myStr
+
+    def setWound(self, character, action, body, actionList):
+        fatigue = self.NameSpaceXI('fatigue', character); f = int(fatigue.text)
+        wounds = self.NameSpaceVI('wounds', character)
+        cWounds = self.NameSpaceXI('current', wounds); cW = int(cWounds.text)
+        mWounds = self.NameSpaceXI('maximum', wounds); mW = int(mWounds.text)
+        total = self.NameSpaceXI('total', character); t = int(total.text)
+        mod = int(actionList[len(actionList)-1])
+        myStr = 'Suffers ' if mod >= 0 else 'Regains '
+        if action == 'fatigue': 
+            myStr += str(mod)+ ' Fatigue '; tie = False
+            for x in range(0, mod):
+                f += 1
+                if f > t: 
+                    f -= 1; cW += 1
+                    if (cW >= 6) and not tie:
+                        deathTest = self.deathTest(cW, body)
+                        if deathTest[0] == 'Dead': tie = True; myStr += deathTest[1]
+                        if deathTest[2] in ['failure', 'riposte', 'tie', 'botch']: tie = True; myStr += deathTest[1]
+                        else: myStr += deathTest[1]
+        if action == 'wounds':
+            myStr += str(int(fabs(mod)))+ ' Wounds '; tie = False
+            if mod > 0:
+                for x in xrange(0, mod):
+                    cW += 1
+                    if (cW >= 6) and not tie:
+                        deathTest = self.deathTest(cW, body)
+                        if deathTest[0] == 'Dead': tie = True; myStr += deathTest[1]
+                        if deathTest[2] in ['failure', 'riposte', 'tie', 'botch']: tie = True; myStr += deathTest[1]
+                        else: myStr += deathTest[1]
+            else: cW += mod
+        if cW < 0: cW = 0
+        if f < 0: f = 0
+        t = f + cW; fatigue.text = str(f); cWounds.text = str(cW); total.text = str(t)
+        if t > mW: myStr += 'You have fallen.'
+        return myStr
+
+    def restPC(self, character, skills, body, action, actionList):
+        if 'd' in actionList[len(actionList)-1]: mod = 0
+        else: mod = int(actionList[len(actionList)-1])
+
+        if action == 'meditate':
+            if not skills.has_key('meditate'):
+                if not skills.has_key('meditation'):
+                    while len(actionList) > 1: actionList.pop()
+                    return 'No skill in Meditation.'
+            magicPoints = self.NameSpaceVI('magic points', character)
+            cMagic = self.NameSpaceXI('current', magicPoints); cM = int(cMagic.text)
+            mMagic = self.NameSpaceXI('maximum', magicPoints); mM = int(mMagic.text)
+            vsDice = self.getSkillDice(skills['meditate']) if skills.has_key('meditate') else self.getSkillDice(skills['meditation'])
+            vsDice += vsDice; vsDice.pop()
+            myStr = 'Meditates, '
+            condition = 'easy'
+            vsCondition = []
+            for x in xrange(1, len(actionList)): 
+                trueDice = self.makeTrueDice(actionList[x])
+                for die in trueDice: vsCondition.append(die)
+            if len(vsCondition) == 0: return 'No Difficulty Set.'
+            magicGained = 0; result = 'success' # Begins loop
+            while result in ['success', 'overwhelm']:
+                vsRoll = self.rollDice(vsDice); conRoll = self.rollDice(vsCondition)
+                if result == 'success': myStr += 'Meditate Skill: ' +self.cleanDice(vsDice)[0]+ ' => ' +vsRoll[0]
+                if result == 'overwhelm':  myStr += ' Rolling Again: ' +self.cleanDice(vsDice)[0]+ ' => ' +vsRoll[0]
+                myStr += ' vs. '+self.cleanDice(vsCondition)[0]+ ' => ' +conRoll[0]
+                result = self.compareTest(vsRoll[1], conRoll[1])
+                if result == 'riposte': myStr += ' Overwhelming failure'
+                else: myStr += ' '+result.capitalize()
+                if result == 'success':
+                    magicGained += 1
+                    break
+                if result == 'overwhelm':
+                    magicGained += 2
+            if magicGained > 0: 
+                myStr += ' Regains '+str(magicGained)+' magic.'
+                cM += magicGained
+            if cM > mM: cM = mM
+            cMagic.text = str(cM)
+            while len(actionList) > 1: actionList.pop()
+
+        if action == 'rest':
+            fatigue = self.NameSpaceXI('fatigue', character); f = int(fatigue.text)
+            wounds = self.NameSpaceVI('wounds', character)
+            cWounds = self.NameSpaceXI('current', wounds); cW = int(cWounds.text)
+            mWounds = self.NameSpaceXI('maximum', wounds); mW = int(mWounds.text)
+            total = self.NameSpaceXI('total', character); t = int(total.text)
+            myStr = 'Rests ' +str(mod)+ ' hours. '
+            f -= mod
+            if f < 0: f = 0
+            if mod >= 8: 
+                myStr += '<b>Roll Magic Dice</b>'
+                if cW > 0:
+                    vsDice = body.find('text').text
+                    vsDice = self.makeTrueDice(vsDice)
+                    c = 9 if cW > 9 else cW
+                    condition = 'easy' if not self.conditions.has_key(actionList[1]) else actionList[1]
+                    vsCondition = self.healingTable[c][self.conditions[condition]]
+                    vsCondition = self.makeTrueDice(vsCondition)
+                    vsRoll = self.rollDice(vsDice); conRoll = self.rollDice(vsCondition)
+                    myStr += ', Roll Wounds; Body: ' +self.cleanDice(vsDice)[0]+ ' => ' +vsRoll[0]
+                    myStr += ' vs. Condition ('+condition.capitalize()+'): '+self.cleanDice(vsCondition)[0]+ ' => ' +conRoll[0]
+                    result = self.compareTest(vsRoll[1], conRoll[1])
+                    if result == 'riposte': myStr += ' Overwhelming failure'
+                    else: myStr += ' '+result.capitalize()
+                    if result in ['success', 'overwhelm']: cW -= 1
+                    if result == 'botch':
+                        cW += 1
+                        deathTest = self.deathTest(cW, body)
+                        if deathTest[0] == 'Dead': return deathTest[1]
+                        else: myStr += deathTest[1]
+            if cW < 0: cW = 0
+            if f < 0: f = 0
+            if t > mW: myStr += 'You have fallen.'
+            t = f + cW; fatigue.text = str(f); cWounds.text = str(cW); total.text = str(t)
+        return myStr
+
+    def dodgeBlock(self, action, ability, actionList, defense, equipment, skillList):
+        optionals = ['guard', 'retreat']
+        blockDice = self.getSkillDice(skillList[action]) if action in skillList.keys() else []
+        speed = self.makeTrueDice( str(ability['speed'].find('text').text) )
+        for s in speed: blockDice.append(s)
+        defendSkill = self.NameSpaceXI(action, defense)
+        defendSkill.text = ', '.join(blockDice)
+        if 'nocover' not in actionList:
+            cover = self.NameSpaceXI('cover', defense)
+            cover = self.makeTrueDice(str(cover.text))
+            for c in cover: blockDice.append(c)
+        if 'retreat' in actionList: blockDice.append('1d8')
+        if action == 'dodge':
+            encumber = self.NameSpaceXI('encumbrance', equipment)
+            try:
+                encumber = float(encumber.text)
+                if encumber < -1:
+                    encumber = int(encumber)
+                    blockDice = self.encumberDice(blockDice, encumber, speed)
+            except: pass
+        if 'guard' in actionList: blockDice.append('+2')
+        return blockDice
+
+    def pcResolve(self, character, defense, skillList, abilityWill):
+        total = self.NameSpaceXI('total', character); t = int(total.text)
+        resolveDice = self.getSkillDice(skillList['resolve']) if 'resolve' in skillList.keys() else []
+        will = self.makeTrueDice( abilityWill.find('text').text )
+        for w in will: resolveDice.append(w)
+        resolveDice = self.cleanDice(resolveDice)[1]
+        defendSkill = self.NameSpaceXI('resolve', defense)
+        defendSkill.text = ', '.join(resolveDice)
+        return resolveDice
+
+
+    ### Data Functions ###
+    def getSkillDice(self, skill, skip=[0]):
+        dice = []; cells = skill.findall('cell')
+        for x in xrange(3, 9):
+            if (cells[x].text != '') or (cells[x].text != None):
+                if x in skip: pass
+                else:
+                    skillDice = self.makeTrueDice(str(cells[x].text))
+                    for s in skillDice: dice.append(s)
+        if len(dice) == 0: return 'No Dice Found!'
+        else: return dice
+
+    def buildAbilities(self, pcSheet):
+        nodes = pcSheet.getiterator('nodehandler')
+        ability = {}
+        for node in nodes:
+            if node.get('name') == 'Body': ability['body'] = node
+            if node.get('name') == 'Speed': ability['speed'] = node
+            if node.get('name') == 'Mind': ability['mind'] = node
+            if node.get('name') == 'Will': ability['will'] = node
+        return ability
+
+    def buildActionList(self, actions):
+        actionLength = len(actions); actionList = []
+        for x in xrange(1, actionLength):
+            if x == actionLength-1: 
+                getMod = self.getMod(actions[x])
+                for action in getMod[0]: actionList.append(str(action))
+                actionList.append(str(getMod[1]))
+            else:
+                for action in self.getMod(actions[x])[0]: actionList.append(str(action))
+        return actionList
+
+    def buildSkillList(self, skills):
+        grid = skills.find('grid')
+        listRows = []
+        for row in grid.findall('row'):
+            listRows.append(row)
+        skillList = {}
+        for x in xrange(1, len(listRows)):
+            if listRows[x].findall('cell')[0].text != None: 
+                skillList[listRows[x].findall('cell')[0].text.lower()] = listRows[x]
+        return skillList
+
+    def buildNodeList(self, pcSheet):
+        nodeList = {}
+        for key in pcSheet.keys():
+            nodes = pcSheet[key].getiterator('nodehandler')
+            for node in nodes:
+                nodeList[node.get('name').lower()] = node
+        return nodeList
+
+
+    ### Test Functions ###
+    def deathTest(self, cW, body):
+        vsDice = body.find('text').text
+        vsDice = self.makeTrueDice(vsDice)
+        vsCondition = self.deathCheck(cW)
+        if vsCondition != []:
+            if vsCondition[0] == 'Dead': myStr = ' You have fallen.'; return [vsCondition[0], myStr, None]
+            vsRoll = self.rollDice(vsDice); conRoll = self.rollDice(vsCondition)
+            myStr = '<br />Death Check: '+self.cleanDice(vsDice)[0]+ ' => ' +vsRoll[0]
+            myStr += ' vs. Death: '+self.cleanDice(vsCondition)[0]+ ' => ' +conRoll[0]
+            result = self.compareTest(vsRoll[1], conRoll[1])
+            if result == 'riposte': myStr += ' Overwhelming failure'
+            else: myStr += ' '+result.capitalize()
+            if result in ['botch', 'failure', 'riposte']:  myStr += ' You have fallen.'
+            else: myStr += ' You have survived.'
+        return [vsCondition[0], myStr, result]
+
+    def passoutTest(self, character, defense, skillList, abilityWill):
+        #mod = int(actionList[len(actionList)-1]) or 0
+        total = self.NameSpaceXI('total', character); t = int(total.text)
+        vsDice = self.getSkillDice(skillList['resolve']) if 'resolve' in skillList.keys() else []
+        will = self.makeTrueDice( abilityWill.find('text').text )
+        for w in will: vsDice.append(w)
+        vsDice = self.cleanDice(vsDice)[1]
+        defendSkill = self.NameSpaceXI('resolve', defense)
+        defendSkill.text = ', '.join(vsDice)
+        vsCondition = self.unconCheck(t)
+        myStr = ''
+        if vsCondition != []:
+            vsRoll = self.rollDice(vsDice); conRoll = self.rollDice(vsCondition)
+            myStr += 'Unconciousness Check: '+self.cleanDice(vsDice)[0]+ ' => ' +vsRoll[0]
+            myStr += ' vs. '+self.cleanDice(vsCondition)[0]+ ' => ' +conRoll[0]
+            result = self.compareTest(vsRoll[1], conRoll[1])
+            if result == 'riposte': myStr += ' Overwhelming failure'
+            else: myStr += ' '+result.capitalize()
+            if result in ['botch', 'failure', 'riposte']:  myStr += ' You have passed out.'
+            else: myStr += ' You have survived.'
+        else: myStr += 'No Unconciousness Check Required!'
+        return myStr
+
+    def unconCheck(self, fatigue):
+        dieList = []
+        if fatigue > 12: fatigue = 12
+        if self.unconTable.has_key(fatigue):
+            dieList.append(self.unconTable[fatigue])
+        return dieList
+
+    def deathCheck(self, wounds):
+        dieList = []
+        if wounds > 13: wounds = 13
+        if self.deathTable.has_key(wounds):
+            dieList.append(self.deathTable[wounds])
+        return dieList
+
+    def compareTest(self, dice1, dice2):
+        ## Do Botch, Tie, Overwhelming.
+        botch = 0
+        for x in xrange(0, len(dice1)):
+            if dice1[x] == 1: botch += 1
+        if botch == len(dice1): return 'botch'
+        botch = 0
+        for x in xrange(0, len(dice2)):
+            if dice2[x] == 1: botch += 1
+        if botch == len(dice2): 
+            if dice1[0] > dice2[0]:
+                if int(dice1[0]) - int(dice2[0]) >= 5: return 'overwhelm'
+                else: return 'success' #result2 = 'botch'
+        #
+        if dice1[0] == dice2[0]: return 'tie'
+        #
+        if dice1[0] > dice2[0]:
+            if int(dice1[0]) - int(dice2[0]) >= 5: return 'overwhelm'
+            else: return 'success'
+        elif dice2[0] >= dice1[0]: 
+            if int(dice2[0]) - int(dice1[0]) >= 5: return 'riposte'
+            else: return 'failure'
+
+    def compareDamage(self, dice1, dice2):
+        # Works like this. [6, 4, 3] vs [5, 5, 2] == 2 Wounds.
+        # [7, 3, 3] vs [6, 3, 3] == 1 Wounds. Ties go to the defender, 1's are not counted.
+        ## Added for future dev.
+        pass
+
+
+    ### Node Functions ###
+    def NameSpaceXI(self, s, node):
+        nodeList = node.getiterator('nodehandler')
+        for node in nodeList:
+            if node.get('name').lower() == s: return node.find('text')
+        return ''
+
+    def NameSpaceVI(self, s, node): ## Sometimes I just need the node. I don't like the name though.
+        nodeList = node.getiterator('nodehandler')
+        for node in nodeList:
+            if node.get('name').lower() == s: return node
+        return ''
+
+    def getNodeValue(self, action, actionList, ability, nodeList, pcSheet, skillList, pcNode):
+        nodePath = actionList[0]
+        weapons = pcSheet['Combat'].getiterator('nodehandler')
+        optionals = ['parry', 'guard', 'retreat']
+        damage = None
+        if nodeList.has_key(action) and nodeList[action] in weapons:
+            toHit = []; damage = []
+            speed = self.makeTrueDice( str(ability['speed'].find('text').text) )
+            for s in speed: toHit.append(s)
+            grid = nodeList[action].find('grid')
+
+            if actionList[1] == 'damage':
+                for row in grid.findall('row'):
+                    cells = row.findall('cell')
+                    if cells[0].text == 'Damage':
+                        trueDice = self.makeTrueDice(cells[1].text)
+                        for die in trueDice: damage.append(die)
+                        damage.append(actionList[len(actionList)-1])
+                    if cells[0].text == 'Name':
+                        weaponName = str(cells[1].text)
+                while len(actionList) > 1: actionList.pop()
+                return weaponName, action, damage
+
+            string = 'Attacks!'
+            for row in grid.findall('row'):
+                cells = row.findall('cell')
+                if cells[0].text == 'Skill': 
+                    weaponSkill = str(cells[1].text).lower()
+                    skillDice = self.getSkillDice(skillList[weaponSkill]) if weaponSkill in skillList.keys() else None
+                    if isinstance(skillDice, list): toHit += skillDice
+                if cells[0].text == 'Damage':
+                    trueDice = self.makeTrueDice(cells[1].text)
+                    for die in trueDice: damage.append(die)
+                    #damage.append(actionList[len(actionList)-1])
+            if 'parry' in actionList:
+                damage = None
+                string = 'Defends'
+                if 'retreat' in actionList: toHit.append('1d8')
+                if 'guard' in actionList: toHit.append(str(int(actionList[len(actionList)-1])+2))
+            return string, toHit, damage
+        return Parse.NameSpaceE('!&'+pcNode.get('name')+'::'+nodePath+'&!'), action, damage
+
+
+    ### pcSheet Functions ###
+    def findSheets(self, initiate):
+        if self.pcSheets.has_key(initiate[0]): return True, self.pcSheets[initiate[0]]
+        pcSheet = Parse.NameSpaceXE('!&'+initiate[0]+'&!')
+        if pcSheet == None: return [False, [initiate[0]], None]
+        else: return [True, self.buildPCSheet(pcSheet), pcSheet]
+        return [False, [initiate[0]], None]
+
+    def buildPCSheet(self, PC):
+        pcSheet = {}
+        nodes = PC.getiterator('nodehandler')
+        for node in nodes:
+            if node.get('name') == 'Character': pcSheet['Character'] = node
+            if node.get('name') == 'Skills': 
+                if node.get('class') == 'rpg_grid_handler': pcSheet['Skills'] = node
+            if node.get('name') == 'General': pcSheet['General'] = node
+            if node.get('name') == 'Abilities': pcSheet['Abilities'] = node
+            if node.get('name') == 'Gifts / Flaws': pcSheet['Gifts / Flaws'] = node
+            if node.get('name') == 'Combat': pcSheet['Combat'] = node
+            if node.get('name') == 'Defense': pcSheet['Defense'] = node
+            if node.get('name') == 'Equipment': pcSheet['Equipment'] = node
+            if node.get('name') == 'Purse': pcSheet['Purse'] = node
+        #print 'pcSheet', len(pcSheet)
+        return pcSheet
+
+    def setPCSheet(self, pcNode, pcSheet, actionList):
+        if len(actionList) < 2: return 'Cannot setPC'
+        while actionList[0].lower() != 'setpc': actionList.pop()
+        self.pcSheets[actionList[1]] = pcSheet
+        self.pcSheets[actionList[1]]['Node'] = pcNode
+        return 'PC Sheet set to '+ actionList[1]
+
+    def delPCSheet(self, pcSheet):
+        del self.pcSheets[pcSheet]
+        return 'PC Sheet '+pcSheet+' deleted.'
+
+    def updatePC(self, pcSheet, skillList, abilitySpeed, actionList):
+        denarii = self.NameSpaceXI('denarii', pcSheet['Purse']); d = int(denarii.text)
+        aureals = self.NameSpaceXI('aureals', pcSheet['Purse']); a = int(aureals.text)
+        while d >= 24: a += 1; d -= 24
+        aureals.text = str(a); denarii.text = str(d)
+        #
+        blockDice = self.getSkillDice(skillList['dodge']) if 'dodge' in skillList.keys() else []
+        speed = self.makeTrueDice( abilitySpeed.find('text').text )
+        for s in speed: blockDice.append(s)
+        blockDice = self.cleanDice(blockDice)[1]
+        defendSkill = self.NameSpaceXI('dodge', pcSheet['Defense'])
+        defendSkill.text = ', '.join(blockDice)
+        #
+        blockDice = self.getSkillDice(skillList['block']) if 'block' in skillList.keys() else []
+        for s in speed: blockDice.append(s)
+        blockDice = self.cleanDice(blockDice)[1]
+        defendSkill = self.NameSpaceXI('block', pcSheet['Defense'])
+        defendSkill.text = ', '.join(blockDice)
+        #
+        fatigue = self.NameSpaceXI('fatigue', pcSheet['Character']); f = int(fatigue.text)
+        wounds = self.NameSpaceVI('wounds', pcSheet['Character'])
+        cWounds = self.NameSpaceXI('current', wounds); cW = int(cWounds.text)
+        mWounds = self.NameSpaceXI('maximum', wounds); mW = int(mWounds.text)
+        total = self.NameSpaceXI('total', pcSheet['Character']); t = int(total.text)
+        t = f + cW; fatigue.text = str(f); cWounds.text = str(cW); total.text = str(t)
+        return 'Updated.'
+
+
+    ### Math Functions ###
+    def getMod(self, action):
+        action = action.split('+')
+        mod = '+'+str(action[1]) if len(action) == 2 else '0'
+        action = action[0]
+        if mod == '0':
+            action = action.split('-')
+            mod = '-'+str(action[1]) if len(action) == 2 else '0'
+            action = action[0]
+        action = [action]
+        return [action, mod]
+
+    def encumberDice(self, diceList, encumber, speed):
+        encumber += 1; speedCap = 12+encumber*2
+        for x in xrange(0, len(diceList)):
+            diceCheck = diceList[x].split('d')
+            try: rolls = int(diceCheck[0])
+            except: continue
+            try: facets = int(diceCheck[1])
+            except: continue
+            if facets > speedCap: facets = speedCap
+            diceList[x] = str(rolls)+'d'+str(facets)
+        return diceList
+
+    def diceModifiers(self, diceList):
+        diceList.sort(); diceList.reverse()
+        dice = [0, 0, 0, 0, 0]
+        getMod = True; mod = 0
+        for dieMod in diceList:
+            try:  mod += int(dieMod); del diceList[diceList.index(dieMod)]
+            except: pass
+        if mod <= 0:
+            diceList.append(str(mod))
+            return diceList
+        for die in diceList: 
+            d = die.split('d')
+            if die == mod: pass
+            elif d[1] == '4': dice[0] += int(d[0])
+            elif d[1] == '6': dice[1] += int(d[0])
+            elif d[1] == '8': dice[2] += int(d[0])
+            elif d[1] == '10': dice[3] += int(d[0])
+            elif d[1] == '12': dice[4] += int(d[0])
+        diceMod = [0, 0, 0, 0, 0, 0]
+        for i in xrange(0, len(dice)):
+            dMod = (mod-(4-i))*dice[i]
+            if dMod < 0: dMod = 0
+            if i == 4: diceMod[5] += mod*dice[i]; diceMod[4] += dice[i]
+            elif i+mod >= 5: diceMod[5] += dMod; diceMod[4] += dice[i]
+            else: diceMod[i+mod] = dice[i]
+        while diceMod[5] > 0:
+            self.applyMod(diceMod)
+        diceMod.pop(); dice = diceMod
+        diceList = []
+        if dice[0] != 0: diceList.append(str(dice[0])+'d4')
+        if dice[1] != 0: diceList.append(str(dice[1])+'d6')
+        if dice[2] != 0: diceList.append(str(dice[2])+'d8')
+        if dice[3] != 0: diceList.append(str(dice[3])+'d10')
+        if dice[4] != 0: diceList.append(str(dice[4])+'d12')
+        diceList.append(str(mod))
+        return diceList
+
+    def applyMod(self, diceMod):
+        for i in xrange(0, 5):
+            while diceMod[i] > 0:
+                if diceMod[5] == 0: break
+                diceMod[5] -= 1
+                if i == 4: diceMod[0] += 1; break
+                else: diceMod[i+1] += 1; diceMod[i] -= 1
+
+
+    ### Dice Functions ###
+    def makeTrueDice(self, dieSet):
+        dice = dieSet.split(',')
+        dieSet = []
+        for die in dice:
+            if 'd' not in die: die = None
+            else:
+                die = die.replace(' ', '')
+                die = die.split('d')
+                try: 
+                    int(die[1])
+                    if die[0] == '': 
+                        if die[1] in self.acceptedDice: die = '1d'.join(die)
+                    else: die = 'd'.join(die)
+                except: die = None
+            if die != None: dieSet.append(die)
+        return dieSet
+
+    def cleanDice(self, diceList):
+        dice = [0, 0, 0, 0, 0]
+        if 'd' in diceList[len(diceList)-1]: mod = '0'
+        else: mod = diceList[len(diceList)-1]
+        for die in diceList: 
+            d = die.split('d')
+            if die == mod: pass
+            elif d[1] == '4': dice[0] += int(d[0])
+            elif d[1] == '6': dice[1] += int(d[0])
+            elif d[1] == '8': dice[2] += int(d[0])
+            elif d[1] == '10': dice[3] += int(d[0])
+            elif d[1] == '12': dice[4] += int(d[0])
+        diceList = []
+        if dice[0] != 0: diceList.append(str(dice[0])+'d4')
+        if dice[1] != 0: diceList.append(str(dice[1])+'d6')
+        if dice[2] != 0: diceList.append(str(dice[2])+'d8')
+        if dice[3] != 0: diceList.append(str(dice[3])+'d10')
+        if dice[4] != 0: diceList.append(str(dice[4])+'d12')
+        cleanList = '['
+        for die in diceList:
+            cleanList += die+', '
+        cleanList += mod+']'
+        return [cleanList, diceList]
+
+    def rollDamage(self, diceList):
+        if 'd' in diceList[len(diceList)-1]: mod = 0; diceList.append('0')
+        else: mod = int(diceList[len(diceList)-1])
+        removeDice = []
+        diceRolls = []
+        for x in xrange(0, len(diceList)-1):
+            dice, facets = diceList[x].split('d')
+            rolls = self.roll(int(dice), int(facets))
+            for roll in rolls: diceRolls.append(roll)
+        diceRolls.sort(); diceRolls.reverse()
+        myStr = '['
+        if mod < 0:
+            for x in xrange(0, int(fabs(mod))): removeDice.append(len(diceRolls)-x-1)
+        if len(diceRolls) > 1:
+            if 0 in removeDice: myStr += '<font color=blue>'+str(diceRolls[0])+'</font>, '
+            else: myStr += '<font color=red>'+str(diceRolls[0])+'</font>, '
+            for x in xrange(1, len(diceRolls)-1):
+                if x in removeDice: myStr += '<font color=blue>'+str(diceRolls[x])+'</font>, '
+                else: myStr += str(diceRolls[x])+', '
+            myStr += '<font color=blue>'+str(diceRolls[len(diceRolls)-1])+'</font>, '+str(mod)+'] '
+        else: 
+            if 0 in removeDice: myStr += '<font color=blue>'+str(diceRolls[0])+'</font>, '+str(mod)+'] '
+            else: myStr += '<font color=red>'+str(diceRolls[0])+'</font>, '+str(mod)+'] '
+        diceRolls.append(mod)
+        return [myStr, diceRolls]
+
+    def rollDice(self, diceList):
+        if 'd' in diceList[len(diceList)-1]: mod = 0; diceList.append('0')
+        else: mod = int(diceList[len(diceList)-1])
+        if mod < 0: rerolls = mod
+        else: rerolls = 0
+        rollSets = []; myStr = ''; result = [100]
+        while rerolls <= 0:
+            diceRolls = []
+            for x in xrange(0, len(diceList)-1):
+                dice, facets = diceList[x].split('d')
+                rolls = self.roll(int(dice), int(facets))
+                for roll in rolls: diceRolls.append(roll)
+            diceRolls.sort(); diceRolls.reverse()
+            rollSets.append(diceRolls); rerolls += 1
+        for diceRolls in rollSets:
+            if result[0] < diceRolls[0]: pass
+            else: result = diceRolls
+            myStr += '['
+            if len(diceRolls) > 1:
+                myStr += '<font color=red>'+str(diceRolls[0])+'</font>, '
+                for x in xrange(1, len(diceRolls)-1): myStr += str(diceRolls[x])+', '
+                myStr += '<font color=blue>'+str(diceRolls[len(diceRolls)-1])+'</font>] '
+            else:  myStr += '<font color=red>'+str(diceRolls[0])+'</font>] '
+        myStr += 'Result: <font color=red>'+str(result[0])+'</font> '
+        return [myStr, result]
+
+    def roll(self, dice, facets):
+        rolls = []
+        for x in range(0, dice): rolls.append(int(random.uniform(1, facets+1)))
+        return rolls
+
+    def stdDie_Class(self, s): ## Not used
+        num_sides = s.split('d')
+        if len(num_sides) > 1: 
+            num = num_sides[0]; sides = num_sides[1]
+            if sides.strip().upper() == 'F': sides = "'f'"
+            try:
+                if int(num) > 100 or int(sides) > 10000: return None
+            except: pass
+            ret = ['(q', num.strip(), "**die_rollers['std'](", sides.strip(), '))']
+            s =  ''.join(ret)
+        return s
+
+die_rollers.register(ironclaw)
--- a/orpg/dieroller/utils.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/dieroller/utils.py	Mon Oct 18 23:48:49 2010 -0500
@@ -32,6 +32,20 @@
 import orpg.dieroller.rollers
 from orpg.dieroller.base import die_rollers
 
+"""
+Die Roller Changes:
+I've made some changes for ease of reading. Below you see the new formula and the old depricated formula. The new formula is easier to understand
+and works a little better with math. Try this: [(2+4)+4d(6+8)+(4*4)] with both formulas. Traipse succeeds, Standard (1.7.1) fails.
+
+The new formula deals only with numbers of the Fudge roller. The math has a required process flow, which is unliked currently by me but I am not
+going to spend more time on at currently to correct it. It occurs when using paranthesis on the facet. If paranthesis are used no modifier can be added
+at the end, but you can added it before the roll.
+
+This is the standard roller formula: (Math D Numbers or Math or Fudge). If that fails the new non_stdDie looks for a regExpression formula inside
+the current die roller, set under the name. So all of that bloat to include the english language in the Gilcrease 1.8.0 remains bloat and Traipse's
+dice can be liberated to do what they want, where they want, when they want.
+"""
+
 class roller_manager(object):
     def __new__(cls):
         it = cls.__dict__.get("__it__")
@@ -55,9 +69,11 @@
 
     def completeMath(self, matches):
         s = matches.group(0)
-        return str(eval(s))
+        try: doMath = str(eval(s))
+        except: doMath = s
+        return doMath
 
-    def stdDieToDClass(self, match):
+    def stdDie_Class(self, match):
         s = match.group(0)
         num_sides = s.split('d')
         if len(num_sides) > 1: 
@@ -72,44 +88,45 @@
             return s
 
     #  Use this to convert ndm-style (3d6) dice to d_base format
-    def convertTheDieString(self, s):
-        """
-        Die Roller Changes:
-        I've made some changes for ease of reading. Below you see the new formula and the old depricated formula. The new formula is easier to understand
-        and works a little better with math. Try this: [(2+4)+4d(6+8)+(4*4)] with both formulas. Traipse succeeds, Standard (1.7.1) fails.
-
-        The new formula deals only with numbers of the Fudge roller. The math has a required process flow, which is unliked currently by me but I am not
-        going to spend more time on at currently to correct it. It occurs when using paranthesis on the facet. If paranthesis are used no modifier can be added
-        at the end, but you can added it before the roll.
-
-        This is the standard roller formula: (Math D Numbers or Math or Fudge). If that fails the new non_stdDie looks for a regExpression formula inside
-        the current die roller, set under the name. So all of that bloat to include the english language in the Gilcrease 1.8.0 remains bloat and Traipse's
-        dice can be liberated to do what they want, where they want, when they want.
-        """
-        self.result = ''
+    def stdDie(self, s):
         math = '[\(0-9\/\*\-\+\)]+'
-        reg = re.compile(math+'d\s*([0-9]+|'+math+'|[fF])')
-
+        reg = re.compile('[0-9]+d\s*([0-9]+|'+math+'|[fF])')
         #reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+") ## Original
-        (result, num_matches) = reg.subn(self.stdDieToDClass, s)
+        try:
+            (result, num_matches) = reg.subn(self.stdDie_Class, s)
+            #print 'main', result, num_matches
+            if num_matches == 0 or result is None:
+                reg = re.compile(math)
+                (result, math_matches) = reg.subn(self.completeMath, s)
+                #print 'math1', result, num_matches
+                reg = re.compile('[0-9]+d\s*([0-9]+|'+math+'|[fF])')
+                (result, num_matches) = reg.subn(self.stdDie_Class, result)
+                #print 'math2', result, num_matches
+        except Exception, e: 
+            print 'Die string conversion failed,', e
+            return s
+        return str(result)
 
-        if num_matches == 0 or result is None:
-            reg = re.compile(math)
-            (result, math_matches) = reg.subn(self.completeMath, s)
+    def nonStdDie(self, s):
+        math = '[\(0-9\/\*\-\+\)]+'
+        reg = re.compile(math)
+        (result, math_matches) = reg.subn(self.completeMath, s)
 
-        if num_matches == 0 or result is None:
-            try:
-                reg = re.compile(die_rollers._rollers[self.getRoller()].regExpression)
-                (result, num_matches) = reg.subn(self.roller_class().non_stdDie, s)
-                self.result = result
-            except: pass
-        return result
+        reg = re.compile(die_rollers._rollers[self.getRoller()].regExpression)
+        (result, num_matches) = reg.subn(self.roller_class().non_stdDie, s) ## Currently skipping math
+
+        if num_matches == 0 or result is None: return s
+        else: return result
 
     def proccessRoll(self, s):
-        v = self.convertTheDieString(s)
-        try: b = str(eval(v))
-        except: 
-            if v == '': b = s
-            else: b = str(v) ##Fail safe for non standard dice.
+        ## Re arranged to allow the non standard dice to use the built in roller methods, 
+        ## not re-written roller methods.
+        b = self.stdDie(s)
+        try: b = str(eval(b))
+        except:
+            b = self.nonStdDie(s)
+            try: b = str(eval(b))
+            except: pass
         return b
 
+
--- a/orpg/gametree/gametree.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/gametree.py	Mon Oct 18 23:48:49 2010 -0500
@@ -702,8 +702,8 @@
         if parent_node == self.root:
             name = xml_element.get('name').replace(u'\xa0', ' ') #Required for XSLT sheets
             xml_element.set('name', name)
-            self.tree_map[xml_element.get('name')] = {}
-            self.tree_map[xml_element.get('name')]['node'] = xml_element
+            self.tree_map[str(xml_element.get('name'))] = {}
+            self.tree_map[str(xml_element.get('name'))]['node'] = xml_element
             xml_element.set('map', '')
         if parent_node != self.root:
             ## Loading XML seems to lag on Grids and Images need a cache for load speed ##
@@ -831,7 +831,8 @@
         self.rename_flag = 0
         if txt != "":
             obj = self.GetPyData(item)
-            obj.xml_root.set('name',txt)
+            #obj.xml.set('name', txt)
+            obj.rename(txt)
         else: evt.Veto()
     
     def on_label_begin(self, evt):
--- a/orpg/gametree/nodehandlers/containers.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/containers.py	Mon Oct 18 23:48:49 2010 -0500
@@ -186,7 +186,7 @@
         if id == P_TITLE:
             txt = self.text[id].GetValue()
             if txt != "":
-                self.handler.xml.set('name',txt)
+                #self.handler.xml.set('name',txt)
                 self.handler.rename(txt)
 
 
@@ -248,7 +248,7 @@
     def on_text(self,evt):
         txt = self.title.GetValue()
         if txt != "":
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
 
 
@@ -343,6 +343,6 @@
     def on_text(self,evt):
         txt = self.title.GetValue()
         if txt != "":
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
 
--- a/orpg/gametree/nodehandlers/core.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/core.py	Mon Oct 18 23:48:49 2010 -0500
@@ -257,10 +257,28 @@
         self.tree.Delete(self.mytree_node)
         return self.xml
 
-    def rename(self,name):
+    def rename(self, name):
         if len(name):
-            self.tree.SetItemText(self.mytree_node,name)
+            self.tree.SetItemText(self.mytree_node, name)
+            old_name = self.xml.get('name')
             self.xml.set('name', name)
+            family_tree = self.tree.get_tree_map(self.mytree_node)
+            family_tree.reverse()
+            self.remap_node(self.mytree_node)
+            if self.tree.tree_map.has_key(old_name):
+                del self.tree.tree_map[old_name]
+                self.tree.tree_map[self.xml.get('name')] = {}
+                self.tree.tree_map[self.xml.get('name')]['node'] = self.xml
+
+    def remap_node(self, xml_root):
+        child, cookie = self.tree.GetFirstChild(xml_root)
+        while child.IsOk():
+            family_tree = self.tree.get_tree_map(child)
+            family_tree.reverse(); family_tree.pop()
+            map_str = '::'.join(family_tree)
+            self.tree.GetPyData(child).xml.set('map', map_str)
+            self.remap_node(child)
+            child, cookie = self.tree.GetNextChild(xml_root, cookie)
 
     def change_icon(self,icon):
         self.xml.set("icon",icon)
@@ -345,7 +363,7 @@
             if bad_txt_found:
                 wx.MessageBox("Some non 7-bit ASCII characters found and stripped","Warning!")
             txt = u_txt
-            print txt, self.handler, self.handler.xml
+            #print txt, self.handler, self.handler.xml
             self.handler.text._set_nodeValue(txt)
 
 
--- a/orpg/gametree/nodehandlers/d20.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/d20.py	Mon Oct 18 23:48:49 2010 -0500
@@ -358,7 +358,7 @@
                 else: mod1 = ""
                 txt = '%s Skill Check: [1d20%s%s]' % (name, mod1, mod)
             chat = self.chat
-            chat.ParsePost(txt,True,True)
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,skill_grid,"Skills")
@@ -409,7 +409,7 @@
             else: mod1 = ""
             chat = self.chat
             txt = '%s check: [1d20%s%s]' % ( name, mod1, mod )
-            chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_mod(self,abbr):
         score = int(self.abilities[abbr].get('base'))
@@ -477,7 +477,7 @@
             else: mod1 = ""
             chat = self.chat
             txt = '%s save: [1d20%s%s]' % (name, mod1, mod)
-            chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,save_grid,"Saves")
@@ -607,14 +607,14 @@
             left = eval( '%s - ( %s )' % ( memrz, use ) )
             if left < 0:
                 txt = '%s Tried to cast %s but has used all of them for today, "Please rest so I can cast more."' % ( cname, name )
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
             else:
                 txt = '%s casts %s ( level %s, "%s" )' % ( cname, name, level, descr )
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
                 s = ''
                 if left != 1: s = 's'
                 txt = '%s can cast %s %d more time%s' % ( cname, name, left, s )
-                self.chat.ParsePost( txt, False, False )
+                Parse.Post( txt, self.chat, False, False )
                 self.spells[ name ].set( 'used', `eval( use )` )
 
     def refresh_spells(self):
@@ -672,14 +672,14 @@
             left = eval( '%s - ( %s )' % ( memrz, use ) )
             if left < 0:
                 txt = '%s Tried to cast %s but has used all of them for today, "Please rest so I can cast more."' % ( cname, name )
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
             else:
                 txt = '%s casts %s ( level %s, "%s" )' % ( cname, name, level, descr )
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
                 s = ''
                 if left != 1: s = 's'
                 txt = '%s can cast %s %d more time%s' % ( cname, name, left, s )
-                self.chat.ParsePost( txt, False, False )
+                Parse.Post( txt, self.chat, False, False )
                 self.spells[ name ].set( 'used', `eval( use )` )
 
     def refresh_spells(self):
@@ -741,29 +741,29 @@
                 numcast = eval('%s / %s' % (left, points))
                 if left < 0:
                     txt = '%s doesnt have enough PowerPoints to use %s' % ( cname, name )
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                 else:
                     txt = '%s uses %s as a Free Talent ( level %s, "%s" )' % ( cname, name, level, descr )
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                     s = ''
                     if left != 1: s = 's'
                     txt = '%s can use %s %d more time%s' % ( cname, name, numcast, s )
-                    self.chat.ParsePost( txt, False, False )
+                    Parse.Post( txt, self.chat, False, False )
                     self.char_hander.set_char_pp('free', left)
             else:
                 left = eval('%s - ( %s )' % ( cpp, points ))
                 numcast = eval('%s / %s' % (left, points))
                 if left < 0:
                     txt = '%s doesnt have enough PowerPoints to use %s' % ( cname, name )
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                 else:
                     txt = '%s uses %s ( level %s, "%s" )' % ( cname, name, level, descr )
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                     s = ''
                     if left != 1: s = 's'
                     txt = '%s can use %s %d more time%s' % ( cname, name, numcast, s )
                     txt += ' - And has %d more Powerpoints left' % (left)
-                    self.chat.ParsePost( txt, False, False )
+                    Parse.Post( txt, self.chat, False, False )
                     self.char_hander.set_char_pp('current1', left)
 
     def refresh_powers(self):
@@ -1007,7 +1007,7 @@
                         txt = 'Critical hit? [1d20%+d] ===> Damage: [%dd%d%+d%s]' \
                               % (bab[i] + attack_mod, crit_mult*num_damage_dice, \
                                  damage_die, crit_mult*damage_mod, extra_damage)
-                        self.chat.ParsePost( txt, True, True )
+                        Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,attack_panel,"Attacks")
--- a/orpg/gametree/nodehandlers/dnd35.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/dnd35.py	Mon Oct 18 23:48:49 2010 -0500
@@ -4,6 +4,7 @@
 from inspect import *  #a 1.9001
 from orpg.dirpath import dir_struct
 from xml.etree.ElementTree import parse
+from orpg.tools.InterParse import Parse
 dnd35_EXPORT = wx.NewId()
 
 ############Global Stuff##############
@@ -396,7 +397,7 @@
             else: mod1 = ""
             chat = self.chat
             txt = '%s check: [1d20%s%s]' % ( name, mod1, mod )
-            chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_mod(self,abbr):
         score = int(self.abilities[abbr].get('base'))
@@ -669,7 +670,7 @@
             else: mod1 = ""
             chat = self.chat
             txt = '%s save: [1d20%s%s]' % (name, mod1, mod)
-            chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,save_grid,"Saves")
@@ -924,7 +925,7 @@
             chat = self.chat
             txt = '%s Skill Check: [1d20%s%s%s] %s' % (
                     name, mod1, mod, acCp, armor)
-            chat.ParsePost(txt,True,True)
+            Parse.Post(txt, self.chat, True, True)
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,skill_grid,"Skills")
@@ -1240,7 +1241,7 @@
         chp = self.xml.get('current')
         mhp = self.xml.get('max')
         txt = '((HP: %s / %s))' % ( chp, mhp )
-        self.chat.ParsePost( txt, True, True )
+        Parse.Post( txt, self.chat, True, True )
 
     def tohtml(self):
         html_str = "<table width=100% border=1 >"
@@ -1442,7 +1443,7 @@
                 if monkLvl == None:     #a 1.5009
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True ) #a 1.5009
+                    Parse.Post( txt, self.chat, True, True ) #a 1.5009
                     return #a 1.5009
                 else:   #a 1.5009
                     lvl=int(monkLvl)
@@ -1456,7 +1457,7 @@
                 if monkLvl == None:     #a 1.5009
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True ) #a 1.5009
+                    Parse.Post( txt, self.chat, True, True ) #a 1.5009
                     return #a 1.5009
                 else:   #a 1.5009
                     lvl=int(monkLvl)
@@ -1470,7 +1471,7 @@
                 if monkLvl == None:     #a 1.5009
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True ) #a 1.5009
+                    Parse.Post( txt, self.chat, True, True ) #a 1.5009
                     return #a 1.5009
                 else:   #a 1.5009
                     lvl=int(monkLvl)
@@ -1515,7 +1516,7 @@
                 if monkLvl == None:
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True ) #a 1.5009
+                    Parse.Post( txt, self.chat, True, True ) #a 1.5009
                     return
                 else:
                     lvl = int(monkLvl)
@@ -1548,7 +1549,7 @@
             else: mod1 = ""
             txt = ' %s Attack Roll: <b>[1d20%s%s%s]</b>' % (name, mod1, base, flu)
             txt += ' ===> Damage: <b>[%s%s]</b>' % (dmg, aStrengthMod)
-            self.chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,attack_panel,"Attacks")
@@ -1918,7 +1919,7 @@
         fac = (int(ac)-(self.root.abilities.get_mod('Dex')))
 
         txt = '((AC: %s Normal, %s Flatfoot))' % ( ac, fac ) #a 1.5002
-        self.chat.ParsePost( txt, True, True )
+        Parse.Post( txt, self.chat, True, True ) #a 1.5009
 
     def tohtml(self):
         html_str = """<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 >
--- a/orpg/gametree/nodehandlers/dnd3e.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/dnd3e.py	Mon Oct 18 23:48:49 2010 -0500
@@ -33,6 +33,7 @@
 from orpg.dirpath import dir_struct
 from orpg.tools.orpg_log import debug
 from xml.etree.ElementTree import parse
+from orpg.tools.InterParse import Parse
 
 dnd3e_EXPORT = wx.NewId()
 ############Global Stuff##############
@@ -763,7 +764,7 @@
             else: mod1 = ""
             chat = self.chat
             txt = '%s save: [1d20%s%s]' % (name, mod1, mod)
-            chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,save_grid,"Saves")
@@ -1016,7 +1017,7 @@
             chat = self.chat
             txt = '%s Skill Check: [1d20%s%s%s] %s' % (
                     name, mod1, mod, acCp, armor)
-            chat.ParsePost(txt,True,True)
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,skill_grid,"Skills")
@@ -1318,7 +1319,7 @@
         chp = self.xml.get('current')
         mhp = self.xml.get('max')
         txt = '((HP: %s / %s))' % ( chp, mhp )
-        self.chat.ParsePost( txt, True, True )
+        Parse.Post( txt, self.chat, True, True )
 
     def tohtml(self):
         html_str = "<table width=100% border=1 >"
@@ -1524,7 +1525,7 @@
                 if monkLvl == None:     #a 1.5009
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True ) #a 1.5009
+                    Parse.Post( txt, self.chat, True, True )
                     return #a 1.5009
                 else:   #a 1.5009
                     lvl=int(monkLvl)
@@ -1538,7 +1539,7 @@
                 if monkLvl == None:
                     txt = 'Attempting to use monk attack, but has no monk '
                     txt += 'levels, please choose a different attack.'
-                    chat.ParsePost( txt, True, True )
+                    Parse.Post( txt, self.chat, True, True )
                     return
                 else: 
                     lvl=int(monkLvl)
@@ -1583,7 +1584,7 @@
             txt = '%s ' % (spacer)
             txt += '%s Attack Roll: <b>[1d20%s%s%s]</b>' % (name, mod1, base, flu)
             txt += ' ===> Damage: <b>[%s%s]</b>' % (dmg, aStrengthMod)
-            self.chat.ParsePost( txt, True, True )
+            Parse.Post( txt, self.chat, True, True )
 
     def get_design_panel(self,parent):
         wnd = outline_panel(parent,self,attack_panel,"Attacks")
@@ -1948,7 +1949,7 @@
         ac = self.get_armor_class()
         fac = (int(ac)-(self.root.abilities.get_mod('Dex')))
         txt = '((AC: %s Normal, %s Flatfoot))' % ( ac, fac ) #a 1.5002
-        self.chat.ParsePost( txt, True, True )
+        Parse.Post( txt, self.chat, True, True )
 
     def tohtml(self):
         html_str = """<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 >
@@ -2168,14 +2169,14 @@
             if left < 0:
                 txt = '%s Tried to cast %s but has used all of them for today,'
                 txt +='"Please rest so I can cast more."' % ( charNameL, name ) #a 1.5002
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
             else:
                 txt = '%s casts %s ( level %s, "%s" )' % ( charNameL, name, level, descr )#a f 1.5002
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
                 s = ''
                 if left != 1: s = 's'
                 txt = '%s can cast %s %d more time%s' % ( charNameL, name, left, s ) #a 1.5002
-                self.chat.ParsePost( txt, False, False )
+                Parse.Post( txt, self.chat, False, False )
                 self.spells[ name ].set( 'used', `eval( use )` )
 
     def refresh_spells(self):
@@ -2257,7 +2258,8 @@
         self.grid.SetCellValue(i,2,name)
         self.grid.SetReadOnly(i,2)
         self.grid.SetCellValue(i,3,type)
-        self.grid.SetReadOnly(i,3)
        self.grid.SetCellValue(i,1,level)
+        self.grid.SetReadOnly(i,3)
+        self.grid.SetCellValue(i,1,level)
         self.grid.SetReadOnly(i,1)
 
     def on_remove(self,evt):
@@ -2344,14 +2346,14 @@
             if left < 0:
                 txt = '%s Tried to cast %s but has used all of them for today,' #m 1.5002 break in 2.
                 txt += "Please rest so I can cast more."' % ( charNameL, name )' #a 1.5002
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
             else:
                 txt = '%s casts %s ( level %s, "%s" )' % ( charNameL, name, level, descr ) #a 5002
-                self.chat.ParsePost( txt, True, False )
+                Parse.Post( txt, self.chat, True, False )
                 s = ''
                 if left != 1: s = 's'
                 txt = '%s can cast %s %d more time%s' % ( charNameL, name, left, s ) #a 1.5002
-                self.chat.ParsePost( txt, False, False )
+                Parse.Post( txt, self.chat, False, False )
                 self.spells[ name ].set( 'used', `eval( use )` )
 
     def refresh_spells(self):
@@ -2401,7 +2403,8 @@
         self.SetSizer(self.sizer)
         self.SetAutoLayout(True)
         self.Fit()
-
        self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
+
+        self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
         self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
         self.Bind(wx.EVT_BUTTON, self.on_refresh_spells, id=30)
         self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
@@ -2531,25 +2534,25 @@
                     #In theory you should never see this -mgt
                     txt = ('%s doesnt have enough PowerPoints to use %s'
                         % ( charNameL, name )) #a 1.5002
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                 else:
                     txt = ('%s uses %s as a Free Talent ( level %s, "%s" )'
                         % ( charNameL, name, level, descr )) #a 1.5002
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                     s = ''
                     if left != 1: s = 's'
                     txt = '%s has %d Free Talent%s left' % ( charNameL, numcast, s ) #a 1.5002
-                    self.chat.ParsePost( txt, False, False )
+                    Parse.Post( txt, self.chat, False, False )
                     self.root.pp.set_char_pp('free',left)       #a 1.5002
             else:
                 left = eval('%s - ( %s )' % ( cpp, points ))
                 #numcast = eval('%s / %s' % (left, points))
                 if left < 0:
                     txt = '%s doesnt have enough PowerPoints to use %s' % ( charNameL, name ) #m 1.5002
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                 else:
                     txt = '%s uses %s ( level %s, "%s" )' % ( charNameL, name, level, descr ) #m 1.5002
-                    self.chat.ParsePost( txt, True, False )
+                    Parse.Post( txt, self.chat, True, False )
                     s = ''
                     if left != 1:
                         s = 's'
@@ -2557,7 +2560,7 @@
                     #txt = '%s can use %s %d more time%s' % ( charNameL, name, numcast, s ) #m 1.5002
                     #txt += ' - And has %d more PowerpointsP left' % (left)
                     txt = '%s has %d more Powerpoint%s' % ( charNameL, left, s ) #m 1.5002
-                    self.chat.ParsePost( txt, False, False )
+                    Parse.Post( txt, self.chat, False, False )
                     self.root.pp.set_char_pp('current1',left)   #a 1.5002
 
     def refresh_powers(self):
--- a/orpg/gametree/nodehandlers/forms.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/forms.py	Mon Oct 18 23:48:49 2010 -0500
@@ -149,7 +149,7 @@
         txt = self.text[id].GetValue()
         if not len(txt): return
         if id == P_TITLE:
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
         elif id == F_HEIGHT or id == F_WIDTH:
             try: int(txt)
@@ -422,7 +422,7 @@
         if id == P_TITLE:
             txt = self.title.GetValue()
             if not len(txt): return
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
         if id == F_TEXT:
             txt = self.text.GetValue()
@@ -927,7 +927,7 @@
         txt = self.text.GetValue()
         if not len(txt): return
         if id == P_TITLE:
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
 
     def on_send_button(self,evt):
@@ -1004,7 +1004,7 @@
         txt = self.text[id].GetValue()
         if not len(txt): return
         if id == P_TITLE:
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
         elif id == P_URL: self.handler.link.set('href',txt)
 
--- a/orpg/gametree/nodehandlers/minilib.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/minilib.py	Mon Oct 18 23:48:49 2010 -0500
@@ -375,7 +375,7 @@
     def on_text(self, evt):
         txt = self.text.GetValue()
         if txt != "":
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
 
 class minilib_grid(wx.grid.Grid):
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Mon Oct 18 23:48:49 2010 -0500
@@ -543,7 +543,7 @@
     def on_text(self,evt):
         txt = self.title.GetValue()
         if txt != "":
-            self.handler.xml.set('name',txt)
+            #self.handler.xml.set('name',txt)
             self.handler.rename(txt)
 
     def refresh_row(self,rowi):
--- a/orpg/orpg_version.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/orpg_version.py	Mon Oct 18 23:48:49 2010 -0500
@@ -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 = "100817-00"
+BUILD = "101018-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/templates/nodes/ironclaw-guide.xml	Mon Oct 18 23:48:49 2010 -0500
@@ -0,0 +1,87 @@
+<nodehandler class="tabber_handler" frame="730,490,139,134" icon="iron-claw" map="" module="containers" name="User Guide" version="1.0"><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="Introduction" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Iron Claw Interactive PC Sheet / Die Roller
+
+The Iron Claw PC Sheet comes with a user guide becuase it is a first of it's kind in Traipse OpenRPG. The PC sheet is designed to interact with the Iron Claw die roller. The die roller uses a set of text based commands to retrieve data from your PC sheet and uses that data to create die rolls and also to make modifications to the PC sheet when you tell it too.
+
+The PC sheet also updates it's data every time you use a command, allowing you to manually edit it and not worry if your changes will take effect.
+
+However, because of this design some restrictions are required to prevent breaking the die rollers interactivity. This small guide will help users get to know what the die roller / pc sheet combo can do, and what can break the roller.
+
+Special thanks goes to Sanguine Productions Ltd for providing the Iron Claw logo image to be used for this sheet. That is awesome!
+
+Ironclaw logo (tm) 1999, 2010 Sanguine Productions. Used with permission from Sanguine Productions Ltd to Knowledge Arcana Mad Mathematics Laboratories, all rights reserved.</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="What NOT To Do" version="1.0"><text hide_title="1" multiline="1" raw_mode="1" send_button="0">Firstly we should go over what can cause the PC Sheet / Die Roller combo to malfunction.
+
+The character sheet is open enough that users can make some modifications to it without fear of breaking it's interactivity with the die roller. Yet, there are certain changes that should not be made or the die roller will not work correctly.
+
+Changing Node Names: 
+In general, users should not change the names of nodes because these are a reference point for the die roller. 
+
+Users are encouraged to change the name of their node from IronClaw to their PC's name. Users are also encouraged to change the name of the Weapon nodes inside the Combat node.
+
+Note: To rename your sheet highlight it and press F2, or right click it and choose Design
+
+Modifying the Skills Grid: 
+Generally this will not be a problem as long as the Race, Careers, and Skills columns remain in their position.
+
+Nodes With the Same Name: 
+This can cause unpredictable problems. While the pc sheet remains open and users can add nodes, it is best to not add nodes with already assigned names.</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="Commands" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Using the die roller is  pretty simple. The die roller integrates NameSpace 2.0 making data retreival rather effeicient.
+
+PC Sheet First:
+Always place the PC sheet's node name first. The default is IronClaw, so that will be used for all examples. You can rename IronClaw. 
+
+Basics:
+The roller syntax is fairly basic. [IronClaw.option]. You will replace 'option' with the various options available, and can even add more options or basic dice rolls. The roller than gathers all of the dice, creating a list of dice to roll, and then rolls those dice.
+
+Example: [IronClaw.mind.2d4] Rolls IronClaw's Mind Dice and 2d4
+
+You can also modify the entire die list with a modifier. [IronClaw.body+3] rolls IronClaw's Body Dice with a +3 Modifier
+
+Basic Options
+.rest+/-# ; Rests a PC for # hours [IronClaw.rest+3]
+.wounds+/-# ; Adds or subtracts # wounds [IronClaw.wounds+3]
+.fatigue ; Works the same as wounds
+.denarii+/-# ; Adds or subtracts # Denarii [IronClaw.denarii+8]
+.aureals ; Works like .denarii for Aureals
+.magic+/-# ; Adds or subtracts # Current Magic [IronClaw.magic-2]
+.magic.#d# Adds #d# to Current Magic [IronClaw.magic.2d4]
+.passout ;  Rolls an Unconsiousness Check
+.meditate.#d# ; Rolls a meditate check vs #d# [IronClaw.meditate.2d4]
+.damage.#d# ; Rolls #d# as Damage Dice [IronClaw.damage.2d4]
+
+Advanced Commands
+.weapona ; Initiates an Attack with 'WeaponA' (See: Weapons &amp; Skills)
+.soak ; Rolls the Soak dice
+.dodge ; Rolls your Dodge dice. Additionally you can add .guard or .retreat
+.block ; Rolls your Block Dice. Additionally you can add .guard or .retreat
+.nocover ; Block and Dodge automatically add Cover unless you add .nocover
+.parry ; When rolled with a Weapon you use that weapon to parry [IronClaw.weapona.parry]</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="Sheet Setup" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Some of the PC Sheet integration will work out of the box with the Iron Claw roller. Other portions require some setup or you will return nothing. Setup is straight forward for the most part.
+
+The Basics:
+If you want your die roller to have the ability to roll ability checks or skill checks, you need to add the dice to their positions in the sheet. You can add multiple dice to one entry using commas (Example: 1d4, 1d8 = 1d4+1d8).
+
+PC Name:
+Be sure to change the Name node in the General form. 
+
+Defense:
+Block and Dodge are automatically filled in each time you use .block or .dodge. You can leave these alone. You will need to fill in Cover, Soak, and Resolve.
+
+Auto Updating:
+The die roller automatically updates some of the data in your node everytime you enter a command. Your Aureals and Denarii are automatically converted, Block and Dodge, and your Total node in Damage is automatically updated. You are free to manually modify your PC sheet and when you roll a die command again the sheet data will update.
+</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="Weapons &amp; Skills" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Weapons &amp; Skills are an extensible feature of the interactive Iron Claw PC sheet. There is no straight forward approach, only guidelines and some mandates that portions of the grids cannot be changed.
+
+Skills:
+With the Iron Claw die roller a user can roll any skill that is in the Skills grid. The default sheet shows only one empty row. Any number of rows can be added (through design mode). The name of the skill goes into the Skill Name column, and the different dice go into the Race, Careers, and Skill columns. Users should not move these columns around. The Favored, Total, Experience, and any columns added can change column positions though.
+
+When rolling a skill the user just rolls with their skill name. 
+Example: [IronClaw.hunter] rolls IronClaw's hunter skill.
+
+Weapons:
+Weapons can be a bit confusing. The weapon attack is Speed + the skill used to weild the weapon.  You need to make sure you have added a row to the Skills grid for the weapon's skill, then add that skill name to the Skill section of the weapon grid. Finally, be sure you have added the damage dice.
+
+To use your weapon the command is the name of the weapon grid. The defaults are weapona, weaponb, and weaponc .. but you can rename them. Note: To rename your weapon grid highlight it and press F2, or right click it and choose Design</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="User Guide" module="forms" name="NameSpace 2.0" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">The IronClaw dieroller also makes use of NameSpace 2.0. This allows you to find your sheet using NameSpace and also to call internal nodes using NameSpace. The syntax for this is extremely easy. Just use the basic roller commands with the NameSpace 2.0 sperator (::)
+
+Example Usage:
+For an example to find your character sheet if it is in the PCSheets folder node, use [PCSheet::IronClaw.command]
+
+You can find internal nodes in much the same way. To output the value of your Denarii node use [IronClaw.Purse::Denarii]
+
+NameSpace 2.0 is a really powerful advancement over it's predocessor in data is retrieved. If you want to know more about NameSpace 2.0 read the User Manual that comes with Traipse.</text></nodehandler></nodehandler>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/templates/nodes/ironclaw.xml	Mon Oct 18 23:48:49 2010 -0500
@@ -0,0 +1,191 @@
+<nodehandler class="tabber_handler" frame="877,516,224,43" icon="iron-claw" map="" module="containers" name="IronClaw" version="1.0"><nodehandler class="tabber_handler" frame="730,490,139,134" icon="iron-claw" map="IronClaw" module="containers" name="User Guide" version="1.0"><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="Introduction" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Iron Claw Interactive PC Sheet / Die Roller
+
+The Iron Claw PC Sheet comes with a user guide becuase it is a first of it's kind in Traipse OpenRPG. The PC sheet is designed to interact with the Iron Claw die roller. The die roller uses a set of text based commands to retrieve data from your PC sheet and uses that data to create die rolls and also to make modifications to the PC sheet when you tell it too.
+
+The PC sheet also updates it's data every time you use a command, allowing you to manually edit it and not worry if your changes will take effect.
+
+However, because of this design some restrictions are required to prevent breaking the die rollers interactivity. This small guide will help users get to know what the die roller / pc sheet combo can do, and what can break the roller.
+
+Special thanks goes to Sanguine Productions Ltd for providing the Iron Claw logo image to be used for this sheet. That is awesome!
+
+Ironclaw logo (tm) 1999, 2010 Sanguine Productions. Used with permission from Sanguine Productions Ltd to Knowledge Arcana Mad Mathematics Laboratories, all rights reserved.</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="What NOT To Do" version="1.0"><text hide_title="1" multiline="1" raw_mode="1" send_button="0">Firstly we should go over what can cause the PC Sheet / Die Roller combo to malfunction.
+
+The character sheet is open enough that users can make some modifications to it without fear of breaking it's interactivity with the die roller. Yet, there are certain changes that should not be made or the die roller will not work correctly.
+
+Changing Node Names: 
+In general, users should not change the names of nodes because these are a reference point for the die roller. 
+
+Users are encouraged to change the name of their node from IronClaw to their PC's name. Users are also encouraged to change the name of the Weapon nodes inside the Combat node.
+
+Note: To rename your sheet highlight it and press F2, or right click it and choose Design
+
+Modifying the Skills Grid: 
+Generally this will not be a problem as long as the Race, Careers, and Skills columns remain in their position.
+
+Nodes With the Same Name: 
+This can cause unpredictable problems. While the pc sheet remains open and users can add nodes, it is best to not add nodes with already assigned names.</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="Commands" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Using the die roller is  pretty simple. The die roller integrates NameSpace 2.0 making data retreival rather effeicient.
+
+PC Sheet First:
+Always place the PC sheet's node name first. The default is IronClaw, so that will be used for all examples. You can rename IronClaw. 
+
+Basics:
+The roller syntax is fairly basic. [IronClaw.option]. You will replace 'option' with the various options available, and can even add more options or basic dice rolls. The roller than gathers all of the dice, creating a list of dice to roll, and then rolls those dice.
+
+Example: [IronClaw.mind.2d4] Rolls IronClaw's Mind Dice and 2d4
+
+You can also modify the entire die list with a modifier. [IronClaw.body+3] rolls IronClaw's Body Dice with a +3 Modifier
+
+Basic Options
+.rest+/-# ; Rests a PC for # hours [IronClaw.rest+3]
+.wounds+/-# ; Adds or subtracts # wounds [IronClaw.wounds+3]
+.fatigue ; Works the same as wounds
+.denarii+/-# ; Adds or subtracts # Denarii [IronClaw.denarii+8]
+.aureals ; Works like .denarii for Aureals
+.magic+/-# ; Adds or subtracts # Current Magic [IronClaw.magic-2]
+.magic.#d# Adds #d# to Current Magic [IronClaw.magic.2d4]
+.passout ;  Rolls an Unconsiousness Check
+.meditate.#d# ; Rolls a meditate check vs #d# [IronClaw.meditate.2d4]
+.damage.#d# ; Rolls #d# as Damage Dice [IronClaw.damage.2d4]
+
+Advanced Commands
+.weapona ; Initiates an Attack with 'WeaponA' (See: Weapons &amp; Skills)
+.soak ; Rolls the Soak dice
+.dodge ; Rolls your Dodge dice. Additionally you can add .guard or .retreat
+.block ; Rolls your Block Dice. Additionally you can add .guard or .retreat
+.nocover ; Block and Dodge automatically add Cover unless you add .nocover
+.parry ; When rolled with a Weapon you use that weapon to parry [IronClaw.weapona.parry]</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="Sheet Setup" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Some of the PC Sheet integration will work out of the box with the Iron Claw roller. Other portions require some setup or you will return nothing. Setup is straight forward for the most part.
+
+The Basics:
+If you want your die roller to have the ability to roll ability checks or skill checks, you need to add the dice to their positions in the sheet. You can add multiple dice to one entry using commas (Example: 1d4, 1d8 = 1d4+1d8).
+
+PC Name:
+Be sure to change the Name node in the General form. 
+
+Defense:
+Block and Dodge are automatically filled in each time you use .block or .dodge. You can leave these alone. You will need to fill in Cover, Soak, and Resolve.
+
+Auto Updating:
+The die roller automatically updates some of the data in your node everytime you enter a command. Your Aureals and Denarii are automatically converted, Block and Dodge, and your Total node in Damage is automatically updated. You are free to manually modify your PC sheet and when you roll a die command again the sheet data will update.
+</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="Weapons &amp; Skills" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">Weapons &amp; Skills are an extensible feature of the interactive Iron Claw PC sheet. There is no straight forward approach, only guidelines and some mandates that portions of the grids cannot be changed.
+
+Skills:
+With the Iron Claw die roller a user can roll any skill that is in the Skills grid. The default sheet shows only one empty row. Any number of rows can be added (through design mode). The name of the skill goes into the Skill Name column, and the different dice go into the Race, Careers, and Skill columns. Users should not move these columns around. The Favored, Total, Experience, and any columns added can change column positions though.
+
+When rolling a skill the user just rolls with their skill name. 
+Example: [IronClaw.hunter] rolls IronClaw's hunter skill.
+
+Weapons:
+Weapons can be a bit confusing. The weapon attack is Speed + the skill used to weild the weapon.  You need to make sure you have added a row to the Skills grid for the weapon's skill, then add that skill name to the Skill section of the weapon grid. Finally, be sure you have added the damage dice.
+
+To use your weapon the command is the name of the weapon grid. The defaults are weapona, weaponb, and weaponc .. but you can rename them. Note: To rename your weapon grid highlight it and press F2, or right click it and choose Design</text></nodehandler><nodehandler class="textctrl_handler" frame="334,152,398,69" icon="note" map="IronClaw::User Guide" module="forms" name="NameSpace 2.0" version="1.0"><text hide_title="1" multiline="1" raw_mode="0" send_button="0">The IronClaw dieroller also makes use of NameSpace 2.0. This allows you to find your sheet using NameSpace and also to call internal nodes using NameSpace. The syntax for this is extremely easy. Just use the basic roller commands with the NameSpace 2.0 sperator (::)
+
+Example Usage:
+For an example to find your character sheet if it is in the PCSheets folder node, use [PCSheet::IronClaw.command]
+
+You can find internal nodes in much the same way. To output the value of your Denarii node use [IronClaw.Purse::Denarii]
+
+NameSpace 2.0 is a really powerful advancement over it's predocessor in data is retrieved. If you want to know more about NameSpace 2.0 read the User Manual that comes with Traipse.</text></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="555,292,533,202" icon="note" map="IronClaw" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">Welcome to the Ironclaw interactive character sheet, made for use with the Ironclaw version 1 die roller.  To get started, input all information into the character sheet just as you would a standard character sheet.
+
+Be mindful of your spelling in the skills list, as it checks the name of the skill you put in when performing operations.  I.E. if you mispelled 'dodge' as 'dogde', and then your character dodges, the roller won't see the dodge skill, and you'll roll only your speed!  For that reason, make sure to use the 'favored' column to note favored uses, so that nothing else is in the "Skill Name" column.
+
+The roller will check for the name you've designated this sheet.  So to change the name from "IronClaw", which is default, right click on the Ironclaw character sheet and select 'Design'.  In the "Tabber" field which comes up, rename the title from "IronClaw" to whatever you prefer, usually your character's first name.
+
+Need more skill slots?  That's easy, press the plus button to the left of your Ironclaw interactive character sheet, right click the 'Skills' menu and select "Design".  From there it is as easy as clicking "Add Row" as often as is needed.
+
+If you don't want this introduction text in your character sheet anymore, expand your character sheet by pressing the plus button to the left of "IronClaw" once again, right click "Introduction" at the top, and select delete.</text></nodehandler><nodehandler class="tabber_handler" frame="400,433,449,113" icon="knight" map="IronClaw" module="containers" name="Character" version="1.0"><nodehandler class="form_handler" frame="339,318,404,57" height="600" icon="chess" map="IronClaw::Character" module="forms" name="General" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Name" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Insert a publically known name here, other names should be in your character background)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Race" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Insert your race, including racial dice, here.  Races are outlined beginning on page 25 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Habitat" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Your chosen habitat goes here, your choices are determined by your race)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Senses" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input your senses here, determined by chosen race and optional racial gifts)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Career 1" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Career type, including die size, goes here.  Career listings begin at page 48 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Career 2" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Career type, including die size, goes here.  Career listings begin at page 48 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Career 3" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Career type, including die size, goes here.  Career listings begin at page 48 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::General" module="forms" name="Career 4" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Career type, including die size, goes here.  Career listings begin at page 48 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,427,653,146" height="600" icon="thief" map="IronClaw::Character" module="forms" name="Abilities" version="1.0" width="400">
+  <nodehandler class="splitter_handler" frame="429,400,0,51" horizontal="0" icon="divider" map="IronClaw::Character::Abilities" module="containers" name="Body / Speed" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Body / Speed" module="forms" name="Body" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">("d#", separate dice by comma)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Body / Speed" module="forms" name="Speed" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">("d#", separate dice by comma)</text></nodehandler></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Abilities" module="containers" name="Mind / Will" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Mind / Will" module="forms" name="Mind" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">("d#", separate dice by comma)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Mind / Will" module="forms" name="Will" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">("d#", separate dice by comma)</text></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Height" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 11 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Size / Weight" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 11 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Dash" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 12 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Stride" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 12 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Lift Bonus" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 12 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities" module="forms" name="Strength Dice" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Rules on page 12 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Abilities" module="containers" name="Magic Points" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Magic Points" module="forms" name="Current" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">0</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Abilities::Magic Points" module="forms" name="Maximum" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Will trait+all wizard traits)</text></nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,90,58" height="600" icon="oriental" map="IronClaw::Character" module="forms" name="Gifts / Flaws" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Gifts / Flaws" module="forms" name="Racial" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(List any racial gifts here.  Races are outlined beginning on page 25 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Gifts / Flaws" module="forms" name="Personal, Social, Esoteric" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(Gifts and flaws begin at page 79 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Gifts / Flaws" module="forms" name="External / Internal" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(Gifts and flaws begin at page 79 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,157,478,112" height="600" icon="orc" map="IronClaw::Character" module="forms" name="Damage" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Damage" module="forms" name="Fatigue" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">0</text></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Damage" module="containers" name="Wounds" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Damage::Wounds" module="forms" name="Current" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">0</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Damage::Wounds" module="forms" name="Maximum" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">12</text></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Damage" module="forms" name="Total" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">0</text></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,359,556,166" height="600" icon="questionhead" map="IronClaw::Character" module="forms" name="Self Improvement" version="1.0" width="400">
+  <nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Self Improvement" module="containers" name="Area 1" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 1" module="forms" name="Area" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input area of training)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 1" module="forms" name="Points" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input the total amount of rewards spent.  The self improvement list is explained on page 251 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Self Improvement" module="containers" name="Area 2" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 2" module="forms" name="Area" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input area of training)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 2" module="forms" name="Points" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input the total amount of rewards spent.  The self improvement list is explained on page 251 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Self Improvement" module="containers" name="Area 3" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 3" module="forms" name="Area" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input area of training)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 3" module="forms" name="Points" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input the total amount of rewards spent.  The self improvement list is explained on page 251 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="splitter_handler" horizontal="0" icon="divider" map="IronClaw::Character::Self Improvement" module="containers" name="Area 4" version="1.0">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 4" module="forms" name="Area" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input area of training)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Character::Self Improvement::Area 4" module="forms" name="Points" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input the total amount of rewards spent.  The self improvement list is explained on page 251 of the Ironclaw legacy book)</text></nodehandler></nodehandler></nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="912,400,298,112" icon="grid" map="IronClaw" module="rpg_grid" name="Skills" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell size="97">Skill Name</cell>
+      <cell size="89">Favored</cell>
+      <cell size="56">Total</cell>
+      <cell size="63">Race Die</cell>
+    <cell size="80">Career Die 1</cell><cell size="82">Career Die 2</cell><cell size="88">Career Die 3</cell><cell size="87">Career Die 4</cell><cell>Skill</cell><cell size="68">Experience</cell></row>
+    <row version="1.0">
+      <cell />
+      <cell />
+      <cell />
+    <cell /><cell /><cell /><cell /><cell /><cell /><cell /></row>
+  <row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="tabber_handler" frame="400,189,635,126" icon="sword" map="IronClaw" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="416,139,700,381" icon="grid" map="IronClaw::Combat" module="rpg_grid" name="WeaponA" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Name</cell>
+      <cell />
+    </row>
+    <row version="1.0">
+      <cell>Skill</cell>
+      <cell />
+    </row>
+  <row version="1.0"><cell>Damage</cell><cell /></row><row version="1.0"><cell>Special</cell><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="415,142,405,368" icon="grid" map="IronClaw::Combat" module="rpg_grid" name="WeaponB" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Name</cell>
+      <cell />
+    </row>
+    <row version="1.0">
+      <cell>Skill</cell>
+      <cell />
+    </row>
+  <row version="1.0"><cell>Damage</cell><cell /></row><row version="1.0"><cell>Special</cell><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="414,140,700,381" icon="grid" map="IronClaw::Combat" module="rpg_grid" name="WeaponC" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Name</cell>
+      <cell />
+    </row>
+    <row version="1.0">
+      <cell>Skill</cell>
+      <cell />
+    </row>
+  <row version="1.0"><cell>Damage</cell><cell /></row><row version="1.0"><cell>Special</cell><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="form_handler" frame="400,130,607,169" height="600" icon="spears" map="IronClaw" module="forms" name="Defense" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Initiative" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input your initiative roll in the form of "d#, d#", initiative is Speed and Mind, or Leadership and tactics, as outlined on page 163 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Block" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(This field will automatically update)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Dodge" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(This field will automatically update)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Cover" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input any cover currently provided from cloaks, shields or the like.  Detailed on page 161 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Soak" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input body dice, modified by gifts or flaws, and armor dice.  Detailed on page 165 of the Ironclaw legacy book)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Defense" module="forms" name="Resolve" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Normally Will dice added to the resolve skill, if any.  Detailed on page 164 of the Ironclaw legacy book)</text></nodehandler></nodehandler><nodehandler class="form_handler" frame="468,575,573,77" height="600" icon="flask" map="IronClaw" module="forms" name="Equipment" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Good Hand" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Weapon in your primary hand)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Off Hand" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Weapon in your off hand)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Head" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Place head armor here)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Body" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Place armor worn on the body here)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Backup" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Place backup weapon here)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Pack" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(List all other items aside from Aureals and Denarii that are in your possession here.  Make sure to calculate your total weight in stones for equipment, so as to be able to work out encumbrance)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Equipment" module="forms" name="Encumbrance" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(points away from being encumbered must be expressed as a negative, points of actual encumbrance should be expressed as a positive, use decimals not fractions)</text></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,76,0,51" height="600" icon="book" map="IronClaw" module="forms" name="Purse" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Purse" module="forms" name="Aureals" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input aureals here as a number, the sheet will automatically convert denarii to aureals if the character gains 24 or more during a transaction)</text></nodehandler><nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="IronClaw::Purse" module="forms" name="Denarii" version="1.0"><text hide_title="0" multiline="0" raw_mode="0" send_button="0">(Input denarii here as a number, the sheet will automatically convert aureals to denarii if the character's denarii go below 0 during a transaction)</text></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="990,625,224,43" icon="note" map="IronClaw" module="forms" name="Character Background" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(This area can be used to write in the history of your character)</text></nodehandler><nodehandler class="textctrl_handler" frame="583,262,288,148" icon="note" map="IronClaw" module="forms" name="Character Description" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="1">(Use this field to create a physical description of what other people see when they look at your character, clicking the 'SEND' button will send that description ot the chat.)</text></nodehandler><nodehandler class="textctrl_handler" frame="400,454,288,148" icon="note" map="IronClaw" module="forms" name="Notes" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">(This is where you can put adventuring notes, iether to keep a tally of adventures past, or as a reminder of things you still need to do.  I.E. - "Pick up eggs, and milk.  Destroy demon overlord.  Stop for mead on the way home.")</text></nodehandler><nodehandler class="textctrl_handler" frame="400,454,288,148" icon="note" map="IronClaw" module="forms" name="Miniatures" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">At the bottom of your character sheet is a folder called "Mini Sizes".  These are meant to be filled with mini's for use with the map.
+
+To put miniatures into the folders, first you must create or have a web-ready image.  Once you have created an image to represent your character and uploaded it to a web address, then go to the map and select the "Miniatures" tab.
+
+Paste the image URL into the url bar there and then click 'Add Miniature'.  The miniature will appear on the map screen.  Once there, right click the image on the map screen and choose 'To Gametree'.  Expand the applicable character sheet, then click and drag the image to the correct size category in the "Miniatures" section of the character sheet, when asked to add it as a child, select yes.  For best results, scale the image in an image manipulation program first, then upload.  However, having Traipse scale the image automatically is possible.  This is achieved through right clicking the image on the map, choosing 'properties' and then changing the numbers for pixel size.  This will result in a less clear image, but also requires less work to get the image to the size you want.
+
+Image sizes:
+There are 3 sizes listed in the mini's folder.  However, you can add more or use less depending on what your game requires.
+
+500 Pixels - This size is for show.  It can be useful in close-up conversations or to help people best understand how the character looks.  Not recommended for use with grids.
+
+90 pixels - Large form mini's are meant for smaller battles with less opponents, allowing for greater detailed mini's to be shown. Recommended for 120 point grids.
+
+50 pixels - Small form mini's are meant for larger battles with a greater number of opponents, the smaller size means more of the battle can be seen on the map at one time.  Recommended for 80 point grids.</text></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="IronClaw" module="containers" name="Mini Sizes" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Mini Sizes" module="containers" name="500 Pixels" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Miniatures" module="containers" name="Group_1" version="1.0">
+  </nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Mini Sizes" module="containers" name="90 Pixels" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Miniatures" module="containers" name="Group_1" version="1.0">
+  </nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Mini Sizes" module="containers" name="40 Pixels" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Miniatures" module="containers" name="Group_1" version="1.0">
+  </nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="IronClaw::Miniatures" module="containers" name="50 Pixels" version="1.0">
+  </nodehandler></nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/tools/InterParse.py	Tue Aug 17 14:53:04 2010 -0500
+++ b/orpg/tools/InterParse.py	Mon Oct 18 23:48:49 2010 -0500
@@ -161,7 +161,7 @@
         reg2 = re.compile("(!=(.*?)=!)")
         """Adding the Parent and Child references to Namespace Internal. Namespace 2.0 is powerful enough it
         should be able to handle them with no problem. For future reference, if you are paying attention, Namespace
-        will include two methods for Internal and External. !@ :: @! and !& :: @! for External and !" :: "! and != :: =!
+        will include two methods for Internal and External. !@ :: @! and !& :: &! for External and !" :: "! and != :: =!
         for Internal. See above Easter Egg for reasoning."""
         reg3 = re.compile("(!!(.*?)!!)")
         reg4 = re.compile("(!#(.*?)#!)")
@@ -181,6 +181,31 @@
             #s = self.NodeParent(s, node)
         return s
 
+    def NameSpaceXE(self, s):
+        reg = re.compile("(!&(.*?)&!)")
+        matches = reg.findall(s)
+        nodeable = ['rpg_grid_handler', 'container_handler', 
+                    'group_handler', 'tabber_handler', 
+                    'splitter_handler', 'form_handler', 'textctrl_handler']
+
+        for i in xrange(0,len(matches)):
+            find = matches[i][1].split('::')
+            node = component.get('tree').xml_root
+            for x in xrange(0, len(find)):
+                namespace = node.getiterator('nodehandler')
+                for node in namespace:
+                    if find[x] == node.get('name'):
+                        if node.get('class') not in nodeable: continue
+                        try:
+                            if self.FutureCheck(node, find[x+1]): break
+                            else: continue
+                        except:
+                            if x == len(find)-1:
+                                return node
+                                break
+                            else: break
+        return None
+
     def NameSpaceE(self, s):
         reg = re.compile("(!&(.*?)&!)")
         matches = reg.findall(s)