# HG changeset patch # User sirebral # Date 1287463729 18000 # Node ID 3bbfd84619c0ab86eca8e4f494d1f7f45112dc70 # Parent 72e0cce81a47f1a6281b097b2d60135e248c8467 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 diff -r 72e0cce81a47 -r 3bbfd84619c0 images/Copyright Notice.txt --- 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 diff -r 72e0cce81a47 -r 3bbfd84619c0 images/icons.xml --- 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 @@ + diff -r 72e0cce81a47 -r 3bbfd84619c0 images/iron-claw.gif Binary file images/iron-claw.gif has changed diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/dieroller/rollers/ironclaw.py --- /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 = ''+self.NameSpaceXI('name', pcSheet['General']).text+ ' ' + 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 += 'Ability; '+action.capitalize()+' ' + 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 += 'Skill; '+action.capitalize()+' ' + + 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 += 'Roll Magic Dice' + 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 = '
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 += ''+str(diceRolls[0])+', ' + else: myStr += ''+str(diceRolls[0])+', ' + for x in xrange(1, len(diceRolls)-1): + if x in removeDice: myStr += ''+str(diceRolls[x])+', ' + else: myStr += str(diceRolls[x])+', ' + myStr += ''+str(diceRolls[len(diceRolls)-1])+', '+str(mod)+'] ' + else: + if 0 in removeDice: myStr += ''+str(diceRolls[0])+', '+str(mod)+'] ' + else: myStr += ''+str(diceRolls[0])+', '+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 += ''+str(diceRolls[0])+', ' + for x in xrange(1, len(diceRolls)-1): myStr += str(diceRolls[x])+', ' + myStr += ''+str(diceRolls[len(diceRolls)-1])+'] ' + else: myStr += ''+str(diceRolls[0])+'] ' + myStr += 'Result: '+str(result[0])+' ' + 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) diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/dieroller/utils.py --- 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 + diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/gametree.py --- 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): diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/containers.py --- 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) diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/core.py --- 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) diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/d20.py --- 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") diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/dnd35.py --- 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 = "" @@ -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: [1d20%s%s%s]' % (name, mod1, base, flu) txt += ' ===> Damage: [%s%s]' % (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 = """
diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/dnd3e.py --- 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 = "
" @@ -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: [1d20%s%s%s]' % (name, mod1, base, flu) txt += ' ===> Damage: [%s%s]' % (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 = """
@@ -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): diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/forms.py --- 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) diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/minilib.py --- 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): diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/gametree/nodehandlers/rpg_grid.py --- 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): diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/orpg_version.py --- 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" diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/templates/nodes/ironclaw-guide.xml --- /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 @@ +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.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.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 & 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]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. +Weapons & 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 DesignThe 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. \ No newline at end of file diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/templates/nodes/ironclaw.xml --- /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 @@ +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.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.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 & 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]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. +Weapons & 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 DesignThe 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.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. + (Insert a publically known name here, other names should be in your character background)(Insert your race, including racial dice, here. Races are outlined beginning on page 25 of the Ironclaw legacy book)(Your chosen habitat goes here, your choices are determined by your race)(Input your senses here, determined by chosen race and optional racial gifts)(Career type, including die size, goes here. Career listings begin at page 48 of the Ironclaw legacy book)(Career type, including die size, goes here. Career listings begin at page 48 of the Ironclaw legacy book)(Career type, including die size, goes here. Career listings begin at page 48 of the Ironclaw legacy book)(Career type, including die size, goes here. Career listings begin at page 48 of the Ironclaw legacy book) + + ("d#", separate dice by comma)("d#", separate dice by comma) + ("d#", separate dice by comma)("d#", separate dice by comma)(Rules on page 11 of the Ironclaw legacy book)(Rules on page 11 of the Ironclaw legacy book)(Rules on page 12 of the Ironclaw legacy book)(Rules on page 12 of the Ironclaw legacy book)(Rules on page 12 of the Ironclaw legacy book)(Rules on page 12 of the Ironclaw legacy book) + 0(Will trait+all wizard traits) + (List any racial gifts here. Races are outlined beginning on page 25 of the Ironclaw legacy book)(Gifts and flaws begin at page 79 of the Ironclaw legacy book)(Gifts and flaws begin at page 79 of the Ironclaw legacy book) + 0 + 0120 + + (Input area of training)(Input the total amount of rewards spent. The self improvement list is explained on page 251 of the Ironclaw legacy book) + (Input area of training)(Input the total amount of rewards spent. The self improvement list is explained on page 251 of the Ironclaw legacy book) + (Input area of training)(Input the total amount of rewards spent. The self improvement list is explained on page 251 of the Ironclaw legacy book) + (Input area of training)(Input the total amount of rewards spent. The self improvement list is explained on page 251 of the Ironclaw legacy book) + + + Skill Name + Favored + Total + Race Die + Career Die 1Career Die 2Career Die 3Career Die 4SkillExperience + + + + + + + + + + + + + Name + + + + Skill + + + DamageSpecial + + + + + + + Name + + + + Skill + + + DamageSpecial + + + + + + + Name + + + + Skill + + + DamageSpecial + + + + + (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)(This field will automatically update)(This field will automatically update)(Input any cover currently provided from cloaks, shields or the like. Detailed on page 161 of the Ironclaw legacy book)(Input body dice, modified by gifts or flaws, and armor dice. Detailed on page 165 of the Ironclaw legacy book)(Normally Will dice added to the resolve skill, if any. Detailed on page 164 of the Ironclaw legacy book) + (Weapon in your primary hand)(Weapon in your off hand)(Place head armor here)(Place armor worn on the body here)(Place backup weapon here)(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)(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) + (Input aureals here as a number, the sheet will automatically convert denarii to aureals if the character gains 24 or more during a transaction)(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)(This area can be used to write in the history of your character)(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.)(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.")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. + + + + + + + + \ No newline at end of file diff -r 72e0cce81a47 -r 3bbfd84619c0 orpg/tools/InterParse.py --- 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)