# HG changeset patch # User sirebral # Date 1292820276 21600 # Node ID d02e9197c06636173d0b5ba7a635a62dd5ca798f # Parent ee890f424e1642fac313557763c9a08dcdba2980 Traipse 'OpenRPG' {101220-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 (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 New ShapeShifter PC Sheet 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 Update to location.py, allows for more portable references when starting Traipse Update to the Features node 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 Server, removing wxPython dependencies where not needed 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 Fix to aliaslib, prevents error caused when SafeHTML is sent None diff -r ee890f424e16 -r d02e9197c066 images/Copyright Notice.txt --- a/images/Copyright Notice.txt Wed May 05 08:55:51 2010 -0500 +++ b/images/Copyright Notice.txt Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 images/iron-claw.gif Binary file images/iron-claw.gif has changed diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/base.py --- a/orpg/dieroller/base.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/base.py Sun Dec 19 22:44:36 2010 -0600 @@ -126,6 +126,7 @@ elif hasattr(other,"sum"): return cmp(self.sum(), other.sum()) else: return UserList.UserList.__cmp__(self,other) + def __rcmp__(self,other): return self.__cmp__(other) @@ -229,7 +230,7 @@ ### di class to handle actual dice class di: - def __init__(self, sides, min=1): + def __init__(self,sides,min=1): self.sides = sides self.history = None self.value = None @@ -263,6 +264,7 @@ def __int__(self): return self.value + def __lt__(self,other): if type(other) == type(3) or type(other) == type(3.0): return self.value < other elif hasattr(other,"value"): return self.value < other.value diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/7sea.py --- a/orpg/dieroller/rollers/7sea.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/7sea.py Sun Dec 19 22:44:36 2010 -0600 @@ -38,12 +38,13 @@ class seventhsea(std): name = "7sea" + regExpression = "[\(0-9\*\-\+\)]+[a-zA-Z]+[0-9]+" def __init__(self,source=[]): std.__init__(self,source) - def non_stdDie(self, s): - print '7th Sea' + def non_stdDie(self, match): + s = match.group(0) num_sides = s.split('k') if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = '10'; target = num_sides[1] diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/__init__.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/alternity.py --- a/orpg/dieroller/rollers/alternity.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/alternity.py Sun Dec 19 22:44:36 2010 -0600 @@ -118,7 +118,6 @@ elif ( self.dieRoll <= self.score / 2 ): self.success = 'G' elif ( self.dieRoll <= self.score ): self.success = 'O' else: self.success = 'F' - if ( self.d20 == 20 ): self.success = 'CF' return myStr def __str__(self): @@ -218,31 +217,17 @@ myStr = " ACTION CHECK : "+myStr successes = {'CS': " CRITICAL SUCCESS", - 'CF': " CRITICAL FAILURE
-2 Step make up bonus next Action Check", + 'CF': " CRITICAL FAILURE", 'A': " AMAZING Success", 'G': " Good Success", 'O': " Ordinary Success", 'F': " Marginal failure"} - if ( self.d20 == 1 ): myStr += successes['CS'] # SEG Dec 19 2009 - myStr += successes[self.success] - if ( self.d20 == 1 ) and (self.success == 'F') : - myStr += " final result ==> " - myStr += successes['O'] # SEG JAN 23 2010 - if ( self.d20 != 1 ) and (self.success == 'F') : - myStr += "
-1 Step make up bonus next Action Check" - + if self.d20 == 1: + myStr += successes['CS'] + myStr += ' (' +successes[self.success]+ ' )' + elif self.d20 == 20: + myStr += successes['CF'] + myStr += ' (' +successes[self.success]+ ' )' + else: myStr += successes[self.success] return myStr - - - - - - - - - - - - - diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/d20.py --- a/orpg/dieroller/rollers/d20.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/d20.py Sun Dec 19 22:44:36 2010 -0600 @@ -43,17 +43,17 @@ std.__init__(self,source) self.DC = DC self.mod = mod - self.append(static_di(mod)) + #self.append(static_di(mod)) def is_success(self): - return ((self.sum() >= self.DC or self.data[0] == 20) and self.data[0] != 1) + return ((self.sum()+self.mod >= self.DC or self.data[0] == 20) and self.data[0] != 1) def __str__(self): myStr = "[" + str(self.data[0]) for a in self.data[1:]: - myStr += "," + myStr += ", " myStr += str(a) - myStr += "] = (" + str(self.sum()) + ")" + myStr += ", "+str(self.mod)+ "] = (" + str(self.sum()+self.mod) + ")" myStr += " vs DC " + str(self.DC) if self.is_success(): myStr += " Success!" else: myStr += " Failure!" diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/earthdawn.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/dieroller/rollers/earthdawn.py Sun Dec 19 22:44:36 2010 -0600 @@ -0,0 +1,165 @@ +## A die roller as used by Earthdawn 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: earthdawn.py +# Author: Prof. Ebral, TaS (Traipse) +# Maintainer: +# Version: +# $Id: earthdawn.py,v Traipse 'Ornery-Orc' prof.ebral Exp $ +# +# Description: Earthdawn Die Roller +# Comissioned by Jacob H. +# + + +from std import std +import random +from orpg.dieroller.base import * + +class earthdawn(std): + name = "earthdawn" + regExpression = "[a-zA-Z]+([0-9]+/[0-9]+|[0-9]+)" + + def __init__(self, source=[]): + std.__init__(self, source) + self.successLevels = self.buildLevels() + + def non_stdDie(self, match): + s = match.group(0) + if s[:4] == 'step' or s[:1] == 's': + dice = s.lower().split('step') + rollType = 'Step' + if len(dice) == 1: dice = s.lower().split('s') + try: step, vs = dice[1].split('/') + except: step, vs = dice[1], 0 + stepRoll = self.stepAlgorithm(step) + elif s[:5] == 'karma' or s[:1] == 'k': + dice = s.lower().split('karma') + rollType = 'Karma' + if len(dice) == 1: dice = s.lower().split('k') + step, vs = dice[1], 0 + stepRoll = self.stepAlgorithm(step) + elif s[:4] == 'test' or s[:1] == 't': + dice = s.lower().split('test') + rollType = 'Test' + if len(dice) == 1: dice = s.lower().split('t') + try: step, vs = dice[1].split('/') + except: return + return self.successTest(step, vs) + return self.finalize(step, stepRoll, vs, rollType) + + def rollDice(self, dice, facets): + rolls = [] + for x in range(0, dice): + roll = self.roll(facets) + while roll >= facets: + rolls.append(roll) + roll = self.roll(facets) + rolls.append(roll) + return rolls + + def roll(self, facets): + return int(random.uniform(1, facets+1)) + + def stepAlgorithm(self, stepRoll): + if stepRoll == 0: return 0 + oneTothree = {'1': -3, '2': -2, '3': -1} + if oneTothree.has_key(stepRoll): + dieList = self.rollDice(1, 6) + dieList[0] += oneTothree[stepRoll] + return dieList + stepRoll = int(stepRoll)-3; self.dieList = [] + for step in xrange(0, stepRoll): self.stepIncrease() + d6s = 0; d8s = 0; d10s = 0; d12s = 0 + dieList = [] + for die in self.dieList: + if die == 6: d6s += 1 + if die == 8: d8s += 1 + if die == 10: d10s += 1 + if die == 12: d12s += 1 + if d6s!= 0: d6s = self.rollDice(d6s, 6); dieList += d6s + if d8s!= 0: d8s = self.rollDice(d8s, 8); dieList += d8s + if d10s!= 0: d10s = self.rollDice(d10s, 10); dieList += d10s + if d12s!= 0: d12s = self.rollDice(d12s, 12); dieList += d12s + return dieList + + def stepIncrease(self): + lowDie = 12 + if len(self.dieList) == 0: self.dieList.append(6); return + for splitDie in self.dieList: + if splitDie < lowDie: lowDie = splitDie + if lowDie == 12: self.dieList[self.dieList.index(lowDie)] = 6; self.dieList.append(6); return + else: self.dieList[self.dieList.index(lowDie)] += 2; return + + def successLevel(self, level, vs): + index = 0 + successLevels = self.successLevels[int(vs)] + for success in successLevels: + if level > success: index = successLevels.index(success)+1 + elif level == success: index = successLevels.index(success) + if index == 0: return 'Pathetic' + if index == 1: return 'Poor' + if index == 2: return 'Average' + if index == 3: return 'Good' + if index == 4: return 'Excellent' + if index >= 5: return 'Extraordinary' + + def successTest(self, stepTotal, vs): + myStr = 'Success Test: ' +stepTotal+ ' vs. ' +vs + successLevel = self.successLevel(int(stepTotal), int(vs)) + myStr += '= ' +successLevel + return myStr + + def finalize(self, step, stepRoll, vs, rollType): + myStr = '' +rollType+' Roll: ' +step + if vs != 0: myStr += ' vs. ' +vs + myStr += ' => ' +str(stepRoll)+ ' (Total: ' + stepTotal = 0 + for step in stepRoll: stepTotal += step + myStr += str(stepTotal) + if vs != 0: + myStr += ' vs. ' +str(vs) + successLevel = self.successLevel(stepTotal, vs) + myStr += ') ' +successLevel + else: myStr += ')' + return myStr + + def buildLevels(self): + successLevels = { + 2: [0, 1, 4, 6, 8, 9], 3: [0, 2, 5, 7, 9, 10], 4: [0, 3, 6, 9, 11, 12], + 5: [1, 4, 7, 10, 13, 14], 6: [1, 5, 8, 12, 16, 17], 7: [2, 6, 10, 14, 18, 19], + 8: [3, 7, 12, 15, 19, 20], 9: [4, 8, 14, 17, 21, 22], 10: [5, 9, 15, 19, 22, 23], + 11: [5, 10, 16, 20, 24, 25], 12: [6, 11, 17, 22, 26, 27], 13: [6, 12, 19, 24, 28, 29], + 14: [7, 13, 20, 25, 30, 31], 15: [8, 14, 22, 26, 30, 31], 16: [9, 15, 23, 27, 32, 33], + 17: [10, 16, 24, 29, 33, 34], 18: [11, 17, 25, 30, 35, 36], 19: [11, 18, 27, 32, 36, 37], + 20: [12, 19, 28, 33, 38, 39], 21: [13, 20, 29, 35, 40, 41], 22: [14, 21, 30, 36, 41, 42], + 23: [15, 22, 32, 37, 42, 43], 24: [15, 23, 33, 38, 43, 44], 25: [16, 24, 34, 40, 45, 46], + 26: [17, 25, 35, 41, 46, 47], 27: [18, 26, 36, 42, 48, 49], 28: [18, 27, 38, 44, 49, 50], + 29: [20, 28, 39, 45, 50, 51], 30: [20, 29, 40, 46, 52, 53], 31: [21, 30, 41, 47, 53, 54], + 32: [22, 31, 42, 48, 54, 55], 33: [23, 32, 44, 50, 56, 57], 34: [23, 33, 45, 51, 57, 58], + 35: [24, 34, 46, 52, 59, 60], 36: [25, 35, 47, 53, 59, 60], 37: [26, 36, 48, 55, 61, 62], + 38: [27, 37, 50, 56, 62, 63], 39: [28, 38, 51, 57, 63, 64], 40: [29, 39, 52, 58, 65, 66], + 41: [28, 40, 52, 60, 70, 71], 42: [29, 41, 53, 61, 71, 72], 43: [30, 42, 54, 63, 72, 73], + 44: [31, 43, 55, 64, 74, 75], 45: [31, 44, 57, 66, 76, 77] + } + return successLevels + +die_rollers.register(earthdawn) + diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/gurps.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/hackmaster.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/hero.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/ironclaw.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/dieroller/rollers/ironclaw.py Sun Dec 19 22:44:36 2010 -0600 @@ -0,0 +1,869 @@ +## 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 >= mW-6) and not tie: + deathTest = self.deathTest(cW+(12-mW), 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 >= mW-6) and not tie: + deathTest = self.deathTest(cW+(12-mW), 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'], [3,8]) if skills.has_key('meditate') else self.getSkillDice(skills['meditation'], [3,8]) + vsDice += vsDice + skDice = self.getSkillDice(skills['meditate'], [3,4,5,6,7]) if skills.has_key('meditate') else self.getSkillDice(skills['meditation'], [3,4,5,6,7]) + if skDice != 'No Dice Found!': vsDice += skDice + 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 ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/mythos.py --- a/orpg/dieroller/rollers/mythos.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/mythos.py Sun Dec 19 22:44:36 2010 -0600 @@ -30,8 +30,8 @@ # Targetthr is the Threshhold target # for compatibility with Mage die rolls. # Threshhold addition by robert t childers - -from std import std + +from std import std from orpg.dieroller.base import * __version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $" @@ -39,6 +39,7 @@ class mythos(std): name = "mythos" + regExpression = "[\(0-9\*\-\+\)]+[a-zA-Z]+[0-9]+" def __init__(self,source=[],target=0,targetthr=0): std.__init__(self,source) @@ -85,7 +86,8 @@ else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")" return myStr - def non_stdDie(self, s): + def non_stdDie(self, match): + s = match.group(0) num_sides = s.split('v') if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = num_sides[1] diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/runequest.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/savage.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/shadowrun.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/sr4.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/srex.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/std.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/trinity.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/wfrpg.py --- a/orpg/dieroller/rollers/wfrpg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/wfrpg.py Sun Dec 19 22:44:36 2010 -0600 @@ -37,11 +37,13 @@ class wfrpg(std): name = "wfrpg" + regExpression = "(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[a-zA-Z]+" def __init__(self, source=[]): std.__init__(self, source) - def non_stdDie(self, s): + def non_stdDie(self, match): + s = match.group(0) self.war_die = {'rec': self.reckless, 'con': self.conservative, 'chr': self.characteristic, diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/wod.py --- a/orpg/dieroller/rollers/wod.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/rollers/wod.py Sun Dec 19 22:44:36 2010 -0600 @@ -38,6 +38,7 @@ class wod(std): name = "wod" + regExpression = "[\(0-9\*\-\+\)]+[a-zA-Z]+[0-9]+" def __init__(self,source=[],target=0,targetthr=0): std.__init__(self,source) @@ -81,13 +82,14 @@ else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")" return myStr - def non_stdDie(self, s): + def non_stdDie(self, match): + s = match.group(0) num_sides = s.split('v') if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = num_sides[1] sides = '10'; target = num_sides[1] ret = ['(', num.strip(), "**die_rollers['wod'](", sides.strip(), ')).vs(', target, ')'] - s = ''.join(ret); return str(eval(s)) + s = ''.join(ret); return s die_rollers.register(wod) diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/rollers/wodex.py diff -r ee890f424e16 -r d02e9197c066 orpg/dieroller/utils.py --- a/orpg/dieroller/utils.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dieroller/utils.py Sun Dec 19 22:44:36 2010 -0600 @@ -1,7 +1,7 @@ #!/usr/bin/env python -# Copyright (C) 2000-2001 The OpenRPG Project +# Copyright (C) 2000-2010 The OpenRPG Project # -# openrpg-dev@lists.sourceforge.net +# 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 @@ -20,20 +20,32 @@ # # File: dieroller/utils.py # Author: OpenRPG Team -# Maintainer: +# Maintainer (Traipse): Tyler Starke # Version: # $Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp $ # # Description: Classes to help manage the die roller # -__version__ = "$Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp Exp $" - import re 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,8 +67,14 @@ def listRollers(self): return die_rollers.keys() - def stdDieToDClass(self, match): - s = match.group(0); self.eval = str(match.string) + def completeMath(self, matches): + s = matches.group(0) + try: doMath = str(eval(s)) + except: doMath = s + return doMath + + def stdDie_Class(self, match): + s = match.group(0) num_sides = s.split('d') if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = num_sides[1] @@ -67,38 +85,48 @@ ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](", sides.strip(), '))'] s = ''.join(ret) - self.eval = s return s - ## Portable Non Standard Die Characters #Prof-Ebral - else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); return s - # Use this to convert ndm-style (3d6) dice to d_base format - def convertTheDieString(self,s): - self.result = '' - reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+") - (result, num_matches) = reg.subn(self.stdDieToDClass, s) - if num_matches == 0 or result is None: - reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[a-zA-Z]+") ## Prof Ebral - (result, num_matches) = reg.subn(self.stdDieToDClass, s) ## Prof Ebral - """try: ## Kinda pointless when you can create new Regular Expressions - s2 = self.roller_class + "(0)." + s ## Broken method - test = eval(s2) - return s2 - except Exception, e: print e; pass""" - self.result = result - try: return self.do_math(s) - except: pass - return result + def stdDie(self, s): + math = '[\(0-9\/\*\-\+\)]+' + reg = re.compile('[0-9]+d\s*([0-9]+|'+math+'|[fF])') + #reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+") ## Original + 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) - def do_math(self, s): - return str(eval(s)) + def nonStdDie(self, s): + math = '[\(0-9\/\*\-\+\)]+' + reg = re.compile(math) + (result, math_matches) = reg.subn(self.completeMath, s) + + 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 == self.eval: 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 ee890f424e16 -r d02e9197c066 orpg/dirpath/dirpath_tools.py --- a/orpg/dirpath/dirpath_tools.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/dirpath/dirpath_tools.py Sun Dec 19 22:44:36 2010 -0600 @@ -1,12 +1,4 @@ -import sys -import os -import errno -from orpg.orpg_wx import * - -if WXLOADED: - class tmpApp(wx.App): - def OnInit(self): - return True +import sys, os, errno #------------------------------------------------------- # void load_paths( dir_struct_reference ) @@ -92,6 +84,8 @@ """Notify the user of directory problems and show directory selection dialog """ + #from orpg.orpg_wx import * + if WXLOADED: app = tmpApp(0) app.MainLoop() diff -r ee890f424e16 -r d02e9197c066 orpg/gametree/gametree.py --- a/orpg/gametree/gametree.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/gametree.py Sun Dec 19 22:44:36 2010 -0600 @@ -47,7 +47,7 @@ import string, urllib, time, os from shutil import copytree, copystat, copy, copyfile -from orpg.orpg_xml import xml +#from orpg.orpg_xml import xml from orpg.tools.validate import validate from orpg.tools.orpg_log import logger, debug from orpg.tools.orpg_settings import settings @@ -239,7 +239,7 @@ emsg = "Gametree Missing!\n"+filename+" cannot be found.\n\n"\ "Would you like to locate it?\n"\ "(Selecting 'No' will cause a new default gametree to be generated)" - self.locate_valid_tree("Gametree Error", emsg) + self.locate_valid_tree("Gametree Error", emsg, filename) return try: self.xml_root = False @@ -265,7 +265,7 @@ emsg = filename+" does not appear to be a valid gametree file.\n\n"\ "Would you like to select a different gametree file to use?\n"\ "(Selecting 'No' will cause a new default gametree to be generated)" - self.locate_valid_tree("Invalid Gametree!", emsg) + self.locate_valid_tree("Invalid Gametree!", emsg, filename) return try: # version = self.xml_root.get("version") @@ -700,8 +700,10 @@ def load_xml(self, xml_element, parent_node, prev_node=None, drag_drop=False): if parent_node == self.root: - self.tree_map[xml_element.get('name')] = {} - self.tree_map[xml_element.get('name')]['node'] = xml_element + name = xml_element.get('name').replace(u'\xa0', ' ') #Required for XSLT sheets + xml_element.set('name', name) + 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 ## @@ -829,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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/chatmacro.py --- a/orpg/gametree/nodehandlers/chatmacro.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/chatmacro.py Sun Dec 19 22:44:36 2010 -0600 @@ -42,15 +42,12 @@ def __init__(self,xml,tree_node): node_handler.__init__(self,xml,tree_node) self.xml = xml - self.text_elem = self.xml.find('text') - self.text = self.text_elem.text - def set_text(self,txt): - self.text = txt + def set_text(self, txt): + self.xml.find('text').text = txt def on_use(self,evt): - txt = self.text - actionlist = txt.split("\n") + actionlist = self.xml.find('text').text.split("\n") for line in actionlist: if(line != ""): if line[0] != "/": ## it's not a slash command @@ -65,8 +62,7 @@ def tohtml(self): title = self.xml.get("name") - txt = self.text - txt = string.replace(txt,'\n',"
") + txt = string.replace(self.xml.find('text').text,'\n',"
") return "

"+title+":
"+txt P_TITLE = wx.NewId() @@ -80,7 +76,7 @@ sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Chat Macro"), wx.VERTICAL) self.text = {} self.text[P_TITLE] = wx.TextCtrl(self, P_TITLE, handler.xml.get('name')) - self.text[P_BODY] = wx.TextCtrl(self, P_BODY, handler.text, style=wx.TE_MULTILINE) + self.text[P_BODY] = wx.TextCtrl(self, P_BODY, handler.xml.find('text').text, style=wx.TE_MULTILINE) sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND) sizer.Add(self.text[P_TITLE], 0, wx.EXPAND) sizer.Add(wx.StaticText(self, -1, "Text Body:"), 0, wx.EXPAND) diff -r ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/containers.py --- a/orpg/gametree/nodehandlers/containers.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/containers.py Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/core.py --- a/orpg/gametree/nodehandlers/core.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/core.py Sun Dec 19 22:44:36 2010 -0600 @@ -214,7 +214,7 @@ pass def on_send_to_chat(self,evt): - self.chat.ParsePost(self.tohtml(),True,True) + Parse.Post(self.tohtml(),False) def on_drop(self, evt): drag_obj = self.tree.drag_obj @@ -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,6 +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 self.handler.text._set_nodeValue(txt) diff -r ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/d20.py --- a/orpg/gametree/nodehandlers/d20.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/d20.py Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/dnd35.py --- a/orpg/gametree/nodehandlers/dnd35.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/dnd35.py Sun Dec 19 22:44:36 2010 -0600 @@ -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############## @@ -275,7 +276,7 @@ nodeName = 'Languages' value = self.lang.GetValue() for node in self.n_list: - if node._get_tagName() == nodeName: node.text = value + if node.tag == nodeName: node.text = value def saveMoney(self, row, col): value = self.grid.GetCellValue(row, col) @@ -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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/dnd3e.py --- a/orpg/gametree/nodehandlers/dnd3e.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/dnd3e.py Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/forms.py --- a/orpg/gametree/nodehandlers/forms.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/forms.py Sun Dec 19 22:44:36 2010 -0600 @@ -30,7 +30,7 @@ from containers import * import orpg.minidom as minidom -from orpg.orpg_xml import xml +#from orpg.orpg_xml import xml from wx.lib.scrolledpanel import ScrolledPanel from orpg.tools.settings import settings from orpg.tools.InterParse import Parse @@ -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) @@ -222,8 +222,9 @@ def tohtml(self): txt = self.get_value() - txt = string.replace(txt,'\n',"
") - if not self.is_hide_title(): txt = ""+self.xml.get("name")+": "+txt + if txt == None: txt = '' + txt = txt.replace('\n','
') + if not self.is_hide_title(): txt = ''+self.xml.get('name')+': '+txt return txt def get_value(self): @@ -421,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() @@ -926,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): @@ -1003,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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/map_miniature_nodehandler.py --- a/orpg/gametree/nodehandlers/map_miniature_nodehandler.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/map_miniature_nodehandler.py Sun Dec 19 22:44:36 2010 -0600 @@ -124,7 +124,7 @@ def tohtml(self): html_str = "
\n" html_str += "
" - html_str += "
" + html_str += "
" html_str += "
" + self.xml.get("name") + "
" return html_str diff -r ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/minilib.py --- a/orpg/gametree/nodehandlers/minilib.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/minilib.py Sun Dec 19 22:44:36 2010 -0600 @@ -37,6 +37,7 @@ import map_miniature_nodehandler import orpg.mapper.map_msg import orpg.minidom as minidom +from orpg.tools.InterParse import Parse # import scriptkit # Constants @@ -44,17 +45,6 @@ FROM_MINILIB_MAP = {'url':'path', 'name':'label', 'unique':None} CORE_ATTRIBUTES = ['name', 'url', 'unique', 'posy', 'posx', 'hide', 'face', 'heading', 'align', 'locked', 'width', 'height'] -ATTRIBUTE_NAME = 'name' -ATTRIBUTE_URL = 'url' -ATTRIBUTE_UNIQUE = 'unique' -ATTRIBUTE_ID = 'id' -ATTRIBUTE_POSX = 'posx' -ATTRIBUTE_POSY = 'posy' - -TAG_MINIATURE = 'miniature' - -COMPONENT_MAP = 'map' -COMPONENT_SESSION = 'session' # # # @@ -100,11 +90,11 @@ """ str = '' str += "" - for mini in self.xml.findall(TAG_MINIATURE): - url = mini.get(ATTRIBUTE_URL) - label = mini.get(ATTRIBUTE_NAME) + for mini in self.xml.findall('miniature'): + url = mini.get('url') + label = mini.get('name') flag = 0 - try: flag = eval( mini.get(ATTRIBUTE_UNIQUE) ) + try: flag = eval( mini.get('unique') ) except: pass show = 'yes' if flag: show = 'no' @@ -133,13 +123,13 @@ for attrib in obj.keys(): key = TO_MINILIB_MAP.get( attrib, attrib ) if key != None: dict[ key ] = obj.get( attrib ) - dict[ ATTRIBUTE_UNIQUE ] = unique + dict[ 'unique' ] = unique self.new_mini( dict ) else: node_handler.on_drop(self, evt) def new_mini( self, data={}, add=1 ): - mini = Element( TAG_MINIATURE ) + mini = Element( 'miniature' ) for key in data.keys(): mini.set( key, data[ key ] ) for key in CORE_ATTRIBUTES: if mini.get( key ) == ('' or None): mini.set( key, '0' ) @@ -154,37 +144,39 @@ def add_leaf( self, mini, icon='gear' ): tree = self.tree icons = tree.icons - key = mini.get( ATTRIBUTE_NAME ) + key = mini.get( 'name' ) self.mydata.append( mini ) def update_leaves( self ): self.mydata = [] - for n in self.xml.findall(TAG_MINIATURE): self.add_leaf( n ) + for n in self.xml.findall('miniature'): self.add_leaf( n ) def on_drag( self, evt ): print 'drag event caught' def send_mini_to_map( self, mini, count=1, addName=True ): if mini == None: return - if mini.get( ATTRIBUTE_URL ) == '' or mini.get( ATTRIBUTE_URL ) == 'http://': - self.chat.ParsePost( self.chat.colorize(self.chat.syscolor, '"%s" is not a valid URL, the mini "%s" will not be added to the map' % ( mini.get( ATTRIBUTE_URL ), mini.get( ATTRIBUTE_NAME ) )) ) + if mini.get( 'url' ) == '' or mini.get( 'url' ) == 'http://': + Parse.Post( self.chat.colorize(self.chat.syscolor, + '"%s" is not a valid URL, the mini "%s" will not be added to the map' % ( + mini.get( 'url' ), mini.get( 'name' ) )) ) return - session = component.get( COMPONENT_SESSION ) + session = component.get( 'session' ) if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER): component.get("chat").InfoPost("You must be either a player or GM to use the miniature Layer") return - map = component.get(COMPONENT_MAP) + canvas = component.get('map') for loop in range( count ): msg = self.get_miniature_XML( mini, addName) msg = str("" + msg + "") - map.new_data( msg ) + canvas.new_data( msg ) session.send( msg ) def get_miniature_XML( self, mini_xml, addName = True ): msg = orpg.mapper.map_msg.mini_msg() - map = component.get( COMPONENT_MAP ) - session = component.get( COMPONENT_SESSION ) - msg.init_prop( ATTRIBUTE_ID, session.get_next_id() ) + canvas = component.get( 'map' ) + session = component.get( 'session' ) + msg.init_prop( 'id', session.get_next_id() ) msg.init_prop('selected', '1')# this will make the mini initially selected for k in mini_xml.keys(): # translate our attributes to map attributes @@ -193,24 +185,24 @@ if not addName and k == 'name': pass else: msg.init_prop( key, mini_xml.get( k ) ) unique = self.is_unique( mini_xml ) - if addName: label = mini_xml.get( ATTRIBUTE_NAME ) + if addName: label = mini_xml.get( 'name' ) else: label = '' return msg.get_all_xml() def is_unique( self, mini ): - unique = mini.get( ATTRIBUTE_UNIQUE ) + unique = mini.get( 'unique' ) val = 0 try: val = eval( unique ) except: val = len( unique ) return val def sanity_check_nodes( self ): - for node in self.xml.findall(TAG_MINIATURE): - if node.get( ATTRIBUTE_POSX ) == '': node.set( ATTRIBUTE_POSX, '0' ) - if node.get( ATTRIBUTE_POSY ) == '': node.set( ATTRIBUTE_POSY, '0' ) + for node in self.xml.findall('miniature'): + if node.get( 'posx' ) == '': node.set( 'posx', '0' ) + if node.get( 'posy' ) == '': node.set( 'posy', '0' ) def get_mini( self, index ): - try: return self.xml.findall(TAG_MINIATURE)[index] + try: return self.xml.findall('miniature')[index] except: return None class mini_handler( node_handler ): @@ -279,7 +271,7 @@ """Returns a dictionary of label => game tree miniature DOM node mappings. """ self.list = [] - for mini in self.handler.xml.findall(TAG_MINIATURE): self.list.append( mini.get( ATTRIBUTE_NAME ) ) + for mini in self.handler.xml.findall('miniature'): self.list.append( mini.get( 'name' ) ) return self.list def on_close(self, evt): @@ -383,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): @@ -407,7 +399,7 @@ self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.select_cell) def update_cols( self ): - for n in self.handler.xml.findall(TAG_MINIATURE): + for n in self.handler.xml.findall('miniature'): for k in n.keys(): if k not in self.keys: self.keys.append( k ) @@ -426,7 +418,7 @@ """Returns the list of 'miniature' DOM elements associated with this miniature library. """ - return self.handler.xml.findall( TAG_MINIATURE ) + return self.handler.xml.findall( 'miniature' ) def add_row( self, count = 1 ): """creates a new miniature node, and then adds it to the current @@ -434,8 +426,8 @@ """ self.AppendRows( count ) node = self.handler.new_mini( { - ATTRIBUTE_NAME :' ', - ATTRIBUTE_URL :'http://'} )# minidom.Element( TAG_MINIATURE ) + 'name' :' ', + 'url' :'http://'} )# minidom.Element( 'miniature' ) self.update_all() #self.handler.xml.append( node ) @@ -446,7 +438,7 @@ """ if self.selectedRow > -1: pos = self.selectedRow - list = self.handler.xml.findall(TAG_MINIATURE) + list = self.handler.xml.findall('miniature') self.handler.xml.remove( list[pos] ) self.DeleteRows( pos, 1 ) @@ -492,7 +484,7 @@ return self.GetTable().GetValue( self.selectedRow, 1 ) def getSelectedSerial( self ): - """Returns the ATTRIBUTE_UNIQUE value for the selected row + """Returns the 'unique' value for the selected row """ return self.GetTable().GetValue( self.selectedRow, 2 ) diff -r ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/rpg_grid.py --- a/orpg/gametree/nodehandlers/rpg_grid.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/rpg_grid.py Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/gametree/nodehandlers/voxchat.py --- a/orpg/gametree/nodehandlers/voxchat.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/gametree/nodehandlers/voxchat.py Sun Dec 19 22:44:36 2010 -0600 @@ -31,7 +31,6 @@ import re, os, string, core from orpg.orpg_windows import * -import core import orpg.tools.scriptkit import orpg.tools.predTextCtrl import orpg.tools.rgbhex diff -r ee890f424e16 -r d02e9197c066 orpg/main.py --- a/orpg/main.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/main.py Sun Dec 19 22:44:36 2010 -0600 @@ -63,7 +63,7 @@ from xml.etree.ElementTree import ElementTree, Element, parse from xml.etree.ElementTree import fromstring, tostring -from orpg.orpg_xml import xml #to be replaced by etree +#from orpg.orpg_xml import xml #to be replaced by etree #################################### @@ -207,7 +207,7 @@ [' -'], [' Tab Styles'], [' Slanted'], - [' Colorful', "check"], + #[' Colorful', "check"], [' Black and White', "check"], [' Aqua', "check"], [' Custom', "check"], @@ -257,7 +257,8 @@ self.mainmenu.SetMenuState('ToolsPasswordManager', True if settings.get('PWMannager') == 'On' else False) tabtheme = settings.get('TabTheme') #This change is stable. TaS. - self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') + if tabtheme == 'slanted&colorful': tabtheme = 'customflat'; settings.change('TabTheme', 'customflat') + #self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", tabtheme == 'slanted&bw') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedAqua", tabtheme == 'slanted&aqua') self.mainmenu.SetMenuState("OpenRPGTabStylesFlatBlackandWhite", tabtheme == 'flat&bw') @@ -323,9 +324,8 @@ #Tab Styles Menus def SetTabStyles(self, *args, **kwargs): - tabtheme = settings.get('TabTheme') #This change is stable. TaS. - self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') + #self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", tabtheme == 'slanted&bw') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedAqua", tabtheme == 'slanted&aqua') self.mainmenu.SetMenuState("OpenRPGTabStylesFlatBlackandWhite", tabtheme == 'flat&bw') @@ -341,7 +341,6 @@ else: try: menu = args[0] except: logger.general('Invalid Syntax for orpgFrame->SetTabStyles(self, *args, **kwargs)'); return - if kwargs.has_key('graidentTo'): graidentTo = kwargs['graidentTo'] else: graidentTo = None if kwargs.has_key('graidentFrom'): graidentFrom = kwargs['graidentFrom'] @@ -365,7 +364,7 @@ for wnd in tabbedwindows: style = wnd.GetWindowStyleFlag() # remove old tabs style - mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_COLORFUL_TABS) + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS ) style &= mirror style |= newstyle wnd.SetWindowStyleFlag(style) @@ -752,11 +751,11 @@ def do_tab_window(self, xml_dom, parent_wnd): # if container window loop through childern and do a recursive call - temp_wnd = orpgTabberWnd(parent_wnd, style=FNB.FNB_ALLOW_FOREIGN_DND) + temp_wnd = orpgTabberWnd(parent_wnd) children = xml_dom.getchildren() for c in children: - wnd = self.build_window(c,temp_wnd) + wnd = self.build_window(c, temp_wnd) name = c.get("name") temp_wnd.AddPage(wnd, name, False) return temp_wnd @@ -936,12 +935,15 @@ except: etreeEl.text = data display_name = self.chat.chat_display_name(player) - if etreeEl.text:self.chat.Post(display_name+etreeEl.text) + if etreeEl.text: + if "is creating room" in etreeEl.text: self.chat.Post(etreeEl.text) + else: self.chat.Post(display_name+etreeEl.text) for child in etreeEl.getchildren(): if child.tag == 'tree': - dlg = wx.MessageDialog(None, component.strip_html(display_name) + ' is trying to send you a tree node. Accept?', 'Question', - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + dlg = wx.MessageDialog(None, + component.strip_html(display_name) + ' is trying to send you a tree node. Accept?', + 'Question', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: dlg.Destroy() self.tree.on_receive_data(tostring(child)) @@ -1129,7 +1131,7 @@ def OnInit(self): component.add('log', logger) - component.add('xml', xml) + #component.add('xml', xml) component.add('settings', settings) component.add('validate', validate) component.add("tabbedWindows", []) diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/background.py --- a/orpg/mapper/background.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/background.py Sun Dec 19 22:44:36 2010 -0600 @@ -211,28 +211,31 @@ else: return '' def layerTakeDOM(self, xml_dom): - type = BG_COLOR - color = xml_dom.getAttribute("color") - logger.debug("color=" + color) - path = urllib.unquote(xml_dom.getAttribute("path")) - logger.debug("path=" + path) - # Begin ted's map changes - if xml_dom.hasAttribute("color"): - r,g,b = self.r_h.rgb_tuple(xml_dom.getAttribute("color")) + bg_type = xml_dom.get("type") + urlpath = xml_dom.get('path') + color = xml_dom.get("color") + + if urlpath != None: + path = urllib.unquote(xml_dom.get("path")) + logger.debug("path=" + path) + + if color != None: + logger.debug("color=" + color) + r,g,b = self.r_h.rgb_tuple(color) self.set_color(cmpColour(r,g,b)) - # End ted's map changes - if xml_dom.hasAttribute("type"): - type = int(xml_dom.getAttribute("type")) - logger.debug("type=" + str(type)) - if type == BG_TEXTURE: + + if bg_type != None: + logger.debug("type=" + bg_type) + bg_type = int(xml_dom.get("type")) + if bg_type == BG_TEXTURE: if path != "": self.set_texture(path) - elif type == BG_IMAGE: + elif bg_type == BG_IMAGE: if path != "": self.set_image(path, 1) - elif type == BG_NONE: self.clear() - if xml_dom.hasAttribute('local') and xml_dom.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(xml_dom.getAttribute('localPath'))): - self.localPath = urllib.unquote(xml_dom.getAttribute('localPath')) + elif bg_type == BG_NONE: self.clear() + if xml_dom.get('local') == 'True' and os.path.exists(urllib.unquote(xml_dom.get('localPath'))): + self.localPath = urllib.unquote(xml_dom.get('localPath')) self.local = True - self.localTime = int(xml_dom.getAttribute('localTime')) + self.localTime = int(xml_dom.get('localTime')) if self.localTime-time.time() <= 144000: file = open(self.localPath, "rb") imgdata = file.read() diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/background_handler.py --- a/orpg/mapper/background_handler.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/background_handler.py Sun Dec 19 22:44:36 2010 -0600 @@ -83,7 +83,7 @@ postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype}) if self.settings.get_setting('LocalorRemote') == 'Remote': - thread.start_new_thread(self.canvas.layers['bg'].upload, + thread.start_new_thread(self.upload, (postdata, dlg.GetPath(), self.bg_type.GetStringSelection())) else: try: min_url = component.get("cherrypy") + filename @@ -97,6 +97,13 @@ self.canvas.send_map_data() self.canvas.Refresh(False) + def upload(self, postdata, filename, imgtype): + self.canvas.layers['bg'].upload(postdata, filename, imgtype) + self.update_info() + self.canvas.send_map_data() + self.canvas.Refresh(False) + return + def update_info(self): bg_type = self.canvas.layers['bg'].get_type() session=self.canvas.frame.session diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/base_msg.py --- a/orpg/mapper/base_msg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/base_msg.py Sun Dec 19 22:44:36 2010 -0600 @@ -29,7 +29,7 @@ from threading import RLock from orpg.networking.mplay_client import * -from xml.etree.ElementTree import ElementTree, Element +from xml.etree.ElementTree import ElementTree, Element, fromstring class map_element_msg_base: # This is a base class @@ -216,20 +216,24 @@ self._from_dom(xml_dom,self.set_prop) def init_from_xml(self,xml): - xml_dom = parseXml(xml) - node_list = xml_dom.getElementsByTagName(self.tagname) + #xml_dom = parseXml(xml) + xml_dom = fromstring(xml) + #node_list = xml_dom.getElementsByTagName(self.tagname) + node_list = xml_dom.findall(self.tagname) if len(node_list) < 1: print "Warning: no <" + self.tagname + "/> elements found in DOM." else: while len(node_list): self.init_from_dom(node_list.pop()) - if xml_dom: xml_dom.unlink() + #if xml_dom: xml_dom.unlink() def set_from_xml(self,xml): - xml_dom = parseXml(xml) - node_list = xml_dom.getElementsByTagName(self.tagname) + #xml_dom = parseXml(xml) + xml_dom = fromstring(xml) + #node_list = xml_dom.getElementsByTagName(self.tagname) + node_list = xml_dom.findall(self.tagname) if len(node_list) < 1: print "Warning: no <" + self.tagname + "/> elements found in DOM." else: while len(node_list): self.set_from_dom(node_list.pop()) - if xml_dom: xml_dom.unlink() + #if xml_dom: xml_dom.unlink() # XML importers end ######################################### diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/fog.py --- a/orpg/mapper/fog.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/fog.py Sun Dec 19 22:44:36 2010 -0600 @@ -27,7 +27,7 @@ from base import * from random import Random from region import * -from orpg.minidom import Element +from xml.etree.ElementTree import Element, tostring import traceback COURSE = 10 @@ -47,8 +47,8 @@ for pairs in string.split( points, ';' ): pair = string.split( pairs, ',' ) p = Element( "point" ) - p.setAttribute( "x", pair[0] ) - p.setAttribute( "y", pair[1] ) + p.set( "x", pair[0] ) + p.set( "y", pair[1] ) result.append( p ) return result @@ -59,23 +59,20 @@ localOutline = "points" elem = Element( "poly" ) if action == "del": - elem.setAttribute( "action", action ) - elem.setAttribute( "outline", localOutline ) + elem.set( "action", action ) + elem.set( "outline", localOutline ) if localOutline == 'points': - list = self.points_to_elements( self.outline ) - for p in list: elem.appendChild( p ) - str = elem.toxml() - elem.unlink() - return str - elem.setAttribute( "action", action ) + foglist = self.points_to_elements( self.outline ) + for p in foglist: elem.append( p ) + return tostring(elem) + elem.set( "action", action ) if localOutline != None: - elem.setAttribute( "outline", localOutline ) + elem.set( "outline", localOutline ) if localOutline == 'points': - list = self.points_to_elements( self.outline ) - for p in list: elem.appendChild( p ) - xml_str = elem.toxml() - elem.unlink() - return xml_str + foglist = self.points_to_elements( self.outline ) + for p in foglist: elem.append( p ) + #xml_str = elem.toxml() + return tostring(elem) class fog_layer(layer_base): def __init__(self, canvas): @@ -223,11 +220,12 @@ if not self.use_fog: self.use_fog = True self.recompute_fog() - if xml_dom.hasAttribute('serial'): self.serial_number = int(xml_dom.getAttribute('serial')) - children = xml_dom._get_childNodes() + serial = xml_dom.get('serial') + if serial != None: self.serial_number = int(serial) + children = xml_dom.getchildren() for l in children: - action = l.getAttribute("action") - outline = l.getAttribute("outline") + action = l.get("action") + outline = l.get("outline") if (outline == "all"): polyline = [IPoint().make(0,0), IPoint().make(self.width-1, 0), IPoint().make(self.width-1, self.height-1), @@ -240,10 +238,10 @@ polyline = [] lastx = None lasty = None - list = l._get_childNodes() + list = l.getchildren() for point in list: - x = point.getAttribute( "x" ) - y = point.getAttribute( "y" ) + x = point.get( "x" ) + y = point.get( "y" ) if (x != lastx or y != lasty): polyline.append(IPoint().make(int(x), int(y))) lastx = x diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/fog_msg.py --- a/orpg/mapper/fog_msg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/fog_msg.py Sun Dec 19 22:44:36 2010 -0600 @@ -27,7 +27,7 @@ from base_msg import * from region import * -from orpg.minidom import Element +from xml.etree.ElementTree import Element, tostring import string class fog_msg(map_element_msg_base): @@ -41,19 +41,17 @@ def get_line(self,outline,action,output_act): elem = Element( "poly" ) - if ( output_act ): elem.setAttribute( "action", action ) - if ( outline == 'all' ) or ( outline == 'none' ): elem.setAttribute( "outline", outline ) + if ( output_act ): elem.set( "action", action ) + if ( outline == 'all' ) or ( outline == 'none' ): elem.set( "outline", outline ) else: - elem.setAttribute( "outline", "points" ) + elem.set( "outline", "points" ) for pair in string.split( outline, ";" ): p = string.split( pair, "," ) point = Element( "point" ) - point.setAttribute( "x", p[ 0 ] ) - point.setAttribute( "y", p[ 1 ] ) - elem.appendChild( point ) - str = elem.toxml() - elem.unlink() - return str + point.set( "x", p[ 0 ] ) + point.set( "y", p[ 1 ] ) + elem.append( point ) + return tostring(elem) # convenience method to use if only this line is modified # outputs a element containing only the changes to this line @@ -83,23 +81,18 @@ str(x2)+","+str(y1)+";"+ str(x2)+","+str(y2)+";"+ str(x1)+","+str(y2),action,output_action) - s = "2): if action=="del": self.fogregion.FromPolygon(polyline,0) else: self.fogregion.FromPolygon(polyline,1) diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/grid.py --- a/orpg/mapper/grid.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/grid.py Sun Dec 19 22:44:36 2010 -0600 @@ -406,19 +406,20 @@ else: return '' def layerTakeDOM(self, xml_dom): - if xml_dom.hasAttribute("color"): - r,g,b = self.r_h.rgb_tuple(xml_dom.getAttribute("color")) + color = xml_dom.get('color') + if color != None: + r,g,b = self.r_h.rgb_tuple(color) self.set_color(cmpColour(r,g,b)) #backwards compatible with non-isometric map formated clients - ratio = RATIO_DEFAULT - if xml_dom.hasAttribute("ratio"): ratio = xml_dom.getAttribute("ratio") - if xml_dom.hasAttribute("mode"): - self.SetMode(int(xml_dom.getAttribute("mode"))) - if xml_dom.hasAttribute("size"): - self.unit_size = int(xml_dom.getAttribute("size")) + ratio = RATIO_DEFAULT if xml_dom.get("ratio") == None else xml_dom.get('ratio') + mode = xml_dom.get('mode') + if mode != None: self.SetMode(int(mode)) + size = xml_dom.get('size') + if size != None: + self.unit_size = int(size) self.unit_size_y = self.unit_size - if xml_dom.hasAttribute("snap"): - if (xml_dom.getAttribute("snap") == 'True') or (xml_dom.getAttribute("snap") == "1"): self.snap = True - else: self.snap = False - if xml_dom.hasAttribute("line"): - self.SetLine(int(xml_dom.getAttribute("line"))) + if (xml_dom.get("snap") == 'True') or (xml_dom.get("snap") == "1"): self.snap = True + else: self.snap = False + line = xml_dom.get('line') + if line != None: self.SetLine(int(line)) + diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/map.py --- a/orpg/mapper/map.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/map.py Sun Dec 19 22:44:36 2010 -0600 @@ -45,6 +45,8 @@ from images import ImageHandler from orpg.orpgCore import component from orpg.tools.orpg_settings import settings +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring # Various marker modes for player tools on the map MARKER_MODE_NONE = 0 @@ -259,21 +261,26 @@ dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1) dc.SetDeviceOrigin(-topleft[0], -topleft[1]) dc.SetUserScale(scale, scale) + + layer_order = [] + for i in xrange (0, len(self.parent.layer_handlers)-1): + if self.parent.layer_tabs.GetPageText(i) in ('Background', 'Fog', 'General'): pass + else: layer_order.append(self.parent.layer_tabs.GetPageText(i)) self.layers['bg'].layerDraw(dc, scale, topleft, clientsize) - self.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], - [clientsize[0]/scale, clientsize[1]/scale]) - self.layers['miniatures'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], - [clientsize[0]/scale, clientsize[1]/scale]) - self.layers['whiteboard'].layerDraw(dc) + + for layer in layer_order: + if layer == 'Grid': self.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], + [clientsize[0]/scale, clientsize[1]/scale]) + if layer == 'Miniatures': self.layers['miniatures'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], + [clientsize[0]/scale, clientsize[1]/scale]) + if layer == 'Whiteboard': self.layers['whiteboard'].layerDraw(dc) + self.layers['fog'].layerDraw(dc, topleft, clientsize) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) - - dc.SelectObject(wx.NullBitmap) - del dc + dc.SelectObject(wx.NullBitmap); del dc wdc = self.preppaint() wdc.DrawBitmap(bmp, topleft[0], topleft[1]) - if settings.get_setting("AlwaysShowMapScale") == "1": self.showmapscale(wdc) try: evt.Skip() @@ -622,15 +629,16 @@ --Snowdog 5/27/03 """ try: - #parse the map DOM - xml_dom = parseXml(xml) + xml_dom = fromstring(xml) if xml_dom == None: return - node_list = xml_dom.getElementsByTagName("map") + node_list = xml_dom.findall("map") + if len(node_list) < 1: + if xml_dom.tag == 'map': node_list = [xml_dom] if len(node_list) < 1: pass else: # set map version to incoming data so layers can convert - self.map_version = node_list[0].getAttribute("version") - action = node_list[0].getAttribute("action") + self.map_version = node_list[0].get("version") + action = node_list[0].get("action") if action == "new": self.layers = {} try: self.layers['bg'] = layer_back_ground(self) @@ -643,37 +651,38 @@ except: pass try: self.layers['fog'] = fog_layer(self) except: pass - sizex = node_list[0].getAttribute("sizex") + sizex = node_list[0].get("sizex") or '' if sizex != "": sizex = int(float(sizex)) sizey = self.size[1] self.set_size((sizex,sizey)) self.size_changed = 0 - sizey = node_list[0].getAttribute("sizey") + sizey = node_list[0].get("sizey") or '' if sizey != "": sizey = int(float(sizey)) sizex = self.size[0] self.set_size((sizex,sizey)) self.size_changed = 0 - children = node_list[0]._get_childNodes() + children = node_list[0].getchildren() #fog layer must be computed first, so that no data is inadvertently revealed for c in children: - name = c._get_nodeName() + name = c.tag if name == "fog": self.layers[name].layerTakeDOM(c) for c in children: - name = c._get_nodeName() + name = c.tag if name != "fog": self.layers[name].layerTakeDOM(c) # all map data should be converted, set map version to current version self.map_version = MAP_VERSION - self.Refresh(False) - xml_dom.unlink() # eliminate circular refs + self.Refresh(True) except: pass def re_ids_in_xml(self, xml): + exception = "\nDeprecated call to: Function re_ids_in_xml, line 679, map.py\nThis can mangle XML, please report!" + logger.exception(exception) new_xml = "" tmp_map = map_msg() - xml_dom = parseXml(str(xml)) - node_list = xml_dom.getElementsByTagName("map") + xml_dom = fromstring(xml) + node_list = xml_dom.findall("map") if len(node_list) < 1: pass else: tmp_map.init_from_dom(node_list[0]) @@ -701,8 +710,7 @@ elif l.tagname == 'circle': id = 'circle-' + self.frame.session.get_next_id() l.init_prop("id", id) new_xml = tmp_map.get_all_xml() - if xml_dom: xml_dom.unlink() - return str(new_xml) + return new_xml class map_wnd(wx.Panel): def __init__(self, parent, id): @@ -714,20 +722,23 @@ self.root_dir = os.getcwd() self.current_layer = 2 self.layer_tabs = orpgTabberWnd(self, style=FNB.FNB_NO_X_BUTTON|FNB.FNB_BOTTOM|FNB.FNB_NO_NAV_BUTTONS) + self.layer_handlers = [] - self.layer_handlers.append(background_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[0],"Background") - self.layer_handlers.append(grid_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[1],"Grid") - self.layer_handlers.append(miniatures_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[2],"Miniatures", True) - self.layer_handlers.append(whiteboard_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[3],"Whiteboard") - self.layer_handlers.append(fog_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[4],"Fog") - self.layer_handlers.append(map_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[5],"General") + self.layer_handlers.append(background_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[0], "Background") + self.layer_handlers.append(grid_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[1], "Grid") + self.layer_handlers.append(miniatures_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[2], "Miniatures", True) + self.layer_handlers.append(whiteboard_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[3], "Whiteboard") + self.layer_handlers.append(fog_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[4], "Fog") + self.layer_handlers.append(map_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[5], "General") self.layer_tabs.SetSelection(2) + + self.layer_order = {1: 'grid', 2: 'miniatures', 3: 'whiteboard'} self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.sizer.Add(self.layer_tabs, 0, wx.EXPAND) @@ -778,9 +789,9 @@ d = wx.FileDialog(self.GetParent(), "Select a file", dir_struct["user"], "", "*.xml", wx.OPEN) if d.ShowModal() == wx.ID_OK: f = open(d.GetPath()) - map_string = f.read() - new_xml = self.canvas.re_ids_in_xml(map_string) - if new_xml: + new_xml = f.read() + f.close() + if new_xml != None: self.canvas.takexml(new_xml) self.canvas.send_map_data("new") self.update_tools() diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/map_msg.py --- a/orpg/mapper/map_msg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/map_msg.py Sun Dec 19 22:44:36 2010 -0600 @@ -53,17 +53,17 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: + if xml_dom.tag == self.tagname: # If this is a map message, look for the "action=new" # Notice we only do this when the root is a map tag - if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new": + if self.tagname == "map" and xml_dom.get("action") == "new": self.clear() # Process all of the properties in each tag - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): - self.init_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - name = c._get_nodeName() + if xml_dom.keys(): + for k in xml_dom.keys(): + self.init_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + name = c.tag if not self.children.has_key(name): if name == "miniatures": self.children[name] = minis_msg(self.p_lock) elif name == "grid": self.children[name] = grid_msg(self.p_lock) @@ -84,16 +84,16 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: + if xml_dom.tag == self.tagname: # If this is a map message, look for the "action=new" # Notice we only do this when the root is a map tag - if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new": + if self.tagname == "map" and xml_dom.get("action") == "new": self.clear() # Process all of the properties in each tag - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - name = c._get_nodeName() + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + name = c.tag if not self.children.has_key(name): if name == "miniatures": self.children[name] = minis_msg(self.p_lock) elif name == "grid": self.children[name] = grid_msg(self.p_lock) diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/miniatures.py --- a/orpg/mapper/miniatures.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/miniatures.py Sun Dec 19 22:44:36 2010 -0600 @@ -344,27 +344,27 @@ else: return '' def takedom(self, xml_dom): - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("posx"): self.pos.x = int(xml_dom.getAttribute("posx")) - if xml_dom.hasAttribute("posy"): self.pos.y = int(xml_dom.getAttribute("posy")) - if xml_dom.hasAttribute("heading"): self.heading = int(xml_dom.getAttribute("heading")) - if xml_dom.hasAttribute("face"): self.face = int(xml_dom.getAttribute("face")) - if xml_dom.hasAttribute("path"): - self.path = urllib.unquote(xml_dom.getAttribute("path")) + self.id = xml_dom.get("id") + if xml_dom.get("posx") != None: self.pos.x = int(xml_dom.get("posx")) + if xml_dom.get("posy") != None: self.pos.y = int(xml_dom.get("posy")) + if xml_dom.get("heading") != None: self.heading = int(xml_dom.get("heading")) + if xml_dom.get("face") != None: self.face = int(xml_dom.get("face")) + if xml_dom.get("path") != None: + self.path = urllib.unquote(xml_dom.get("path")) self.set_bmp(ImageHandler.load(self.path, 'miniature', self.id)) - if xml_dom.hasAttribute("locked"): - if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True': self.locked = True + if xml_dom.get("locked") != None: + if xml_dom.get("locked") == '1' or xml_dom.get("locked") == 'True': self.locked = True else: self.locked = False - if xml_dom.hasAttribute("hide"): - if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True': self.hide = True + if xml_dom.get("hide") != None: + if xml_dom.get("hide") == '1' or xml_dom.get("hide") == 'True': self.hide = True else: self.hide = False - if xml_dom.hasAttribute("label"): self.label = xml_dom.getAttribute("label") - if xml_dom.hasAttribute("zorder"): self.zorder = int(xml_dom.getAttribute("zorder")) - if xml_dom.hasAttribute("align"): - if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True': self.snap_to_align = 1 + if xml_dom.get("label") != None: self.label = xml_dom.get("label") + if xml_dom.get("zorder") != None: self.zorder = int(xml_dom.get("zorder")) + if xml_dom.get("align") != None: + if xml_dom.get("align") == '1' or xml_dom.get("align") == 'True': self.snap_to_align = 1 else: self.snap_to_align = 0 - if xml_dom.hasAttribute("width"): self.width = int(xml_dom.getAttribute("width")) - if xml_dom.hasAttribute("height"): self.height = int(xml_dom.getAttribute("height")) + if xml_dom.get("width") != None: self.width = int(xml_dom.get("width")) + if xml_dom.get("height") != None: self.height = int(xml_dom.get("height")) ##----------------------------- ## miniature layer @@ -489,36 +489,36 @@ else: return "" def layerTakeDOM(self, xml_dom): - if xml_dom.hasAttribute('serial'): - self.serial_number = int(xml_dom.getAttribute('serial')) - children = xml_dom._get_childNodes() + if xml_dom.get('serial') != None: + self.serial_number = int(xml_dom.get('serial')) + children = xml_dom.getchildren() for c in children: - action = c.getAttribute("action") - id = c.getAttribute('id') + action = c.get("action") + id = c.get('id') if action == "del": mini = self.get_miniature_by_id(id) if mini: self.miniatures.remove(mini); del mini elif action == "new": - pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy'))) - path = urllib.unquote(c.getAttribute('path')) - label = c.getAttribute('label') + pos = cmpPoint(int(c.get('posx')),int(c.get('posy'))) + path = urllib.unquote(c.get('path')) + label = c.get('label') height = width = heading = face = snap_to_align = zorder = 0 locked = hide = False - if c.hasAttribute('height'): height = int(c.getAttribute('height')) - if c.hasAttribute('width'): width = int(c.getAttribute('width')) - if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1': locked = True - if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1': hide = True - if c.getAttribute('heading'): heading = int(c.getAttribute('heading')) - if c.hasAttribute('face'): face = int(c.getAttribute('face')) - if c.hasAttribute('align'): snap_to_align = int(c.getAttribute('align')) - if c.getAttribute('zorder'): zorder = int(c.getAttribute('zorder')) + if c.get('height') != None: height = int(c.get('height')) + if c.get('width') != None: width = int(c.get('width')) + if c.get('locked') == 'True' or c.get('locked') == '1': locked = True + if c.get('hide') == 'True' or c.get('hide') == '1': hide = True + if c.get('heading') != None: heading = int(c.get('heading')) + if c.get('face') != None: face = int(c.get('face')) + if c.get('align') != None: snap_to_align = int(c.get('align')) + if c.get('zorder') != None: zorder = int(c.get('zorder')) min = BmpMiniature(id, path, ImageHandler.load(path, 'miniature', id), pos, heading, face, label, locked, hide, snap_to_align, zorder, width, height) self.miniatures.append(min) - if c.hasAttribute('local') and c.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(c.getAttribute('localPath'))): - localPath = urllib.unquote(c.getAttribute('localPath')) + if c.get('local') == 'True' and os.path.exists(urllib.unquote(c.get('localPath'))): + localPath = urllib.unquote(c.get('localPath')) local = True - localTime = float(c.getAttribute('localTime')) + localTime = float(c.get('localTime')) if localTime-time.time() <= 144000: file = open(localPath, "rb") imgdata = file.read() diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/miniatures_msg.py --- a/orpg/mapper/miniatures_msg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/miniatures_msg.py Sun Dec 19 22:44:36 2010 -0600 @@ -79,11 +79,11 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.init_prop(k,xml_dom.getAttribute(k)) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.init_prop(k,xml_dom.get(k)) - for c in xml_dom._get_childNodes(): + for c in xml_dom.getchildren(): mini = mini_msg(self.p_lock) try: mini.init_from_dom(c) except Exception, e: print e; continue @@ -103,10 +103,10 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): mini = mini_msg(self.p_lock) try: mini.set_from_dom(c) except Exception, e: print e; continue diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/whiteboard.py --- a/orpg/mapper/whiteboard.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/whiteboard.py Sun Dec 19 22:44:36 2010 -0600 @@ -46,7 +46,7 @@ self.scale = 1 self.r_h = RGBHex() self.selected = False - self.text_string = text_string + self.text_string = text_string.replace('"', '"').replace("'", ''') self.id = id self.weight = int(weight) self.pointsize = int(pointsize) @@ -95,7 +95,8 @@ # Draw text (w,x,y,z) = self.get_rect(dc) dc.SetFont(self.font) - dc.DrawText(self.text_string, self.posx, self.posy) + text_string = self.text_string.replace('"', '"').replace(''', "'") + dc.DrawText(text_string, self.posx, self.posy) dc.SetTextForeground(wx.Colour(0,0,0)) def toxml(self, action="update"): @@ -119,21 +120,21 @@ else: return '' def takedom(self, xml_dom): - self.text_string = xml_dom.getAttribute("text_string") - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("posy"): self.posy = int(xml_dom.getAttribute("posy")) - if xml_dom.hasAttribute("posx"): self.posx = int(xml_dom.getAttribute("posx")) - if xml_dom.hasAttribute("weight"): - self.weight = int(xml_dom.getAttribute("weight")) + self.text_string = xml_dom.get("text_string") + self.id = xml_dom.get("id") + if xml_dom.get("posy") != None: self.posy = int(xml_dom.get("posy")) + if xml_dom.get("posx") != None: self.posx = int(xml_dom.get("posx")) + if xml_dom.get("weight"): + self.weight = int(xml_dom.get("weight")) self.font.SetWeight(self.weight) - if xml_dom.hasAttribute("style"): - self.style = int(xml_dom.getAttribute("style")) + if xml_dom.get("style") != None: + self.style = int(xml_dom.get("style")) self.font.SetStyle(self.style) - if xml_dom.hasAttribute("pointsize"): - self.pointsize = int(xml_dom.getAttribute("pointsize")) + if xml_dom.get("pointsize") != None: + self.pointsize = int(xml_dom.get("pointsize")) self.font.SetPointSize(self.pointsize) - if xml_dom.hasAttribute("color") and xml_dom.getAttribute("color") != '': - self.textcolor = xml_dom.getAttribute("color") + if xml_dom.get("color") != None and xml_dom.get("color") != '': + self.textcolor = xml_dom.get("color") if self.textcolor == '#0000000': self.textcolor = '#000000' class WhiteboardLine: @@ -231,16 +232,16 @@ return '' def takedom(self, xml_dom): - self.line_string = xml_dom.getAttribute("line_string") - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("upperleftx"): self.upperleft.x = int(xml_dom.getAttribute("upperleftx")) - if xml_dom.hasAttribute("upperlefty"): self.upperleft.y = int(xml_dom.getAttribute("upperlefty")) - if xml_dom.hasAttribute("lowerrightx"): self.lowerright.x = int(xml_dom.getAttribute("lowerrightx")) - if xml_dom.hasAttribute("lowerrighty"): self.lowerright.y = int(xml_dom.getAttribute("lowerrighty")) - if xml_dom.hasAttribute("color") and xml_dom.getAttribute("color") != '': - self.linecolor = xml_dom.getAttribute("color") + self.line_string = xml_dom.get("line_string") + self.id = xml_dom.get("id") + if xml_dom.get("upperleftx") != None: self.upperleft.x = int(xml_dom.get("upperleftx")) + if xml_dom.get("upperlefty") != None: self.upperleft.y = int(xml_dom.get("upperlefty")) + if xml_dom.get("lowerrightx") != None: self.lowerright.x = int(xml_dom.get("lowerrightx")) + if xml_dom.get("lowerrighty") != None: self.lowerright.y = int(xml_dom.get("lowerrighty")) + if xml_dom.get("color") != None and xml_dom.get("color") != '': + self.linecolor = xml_dom.get("color") if self.linecolor == '#0000000': self.linecolor = '#000000' - if xml_dom.hasAttribute("width"): self.linewidth = int(xml_dom.getAttribute("width")) + if xml_dom.get("width") != None: self.linewidth = int(xml_dom.get("width")) ##----------------------------- ## whiteboard layer @@ -369,7 +370,7 @@ def add_text(self, text_string, pos, style, pointsize, weight, color="#000000"): id = 'text-' + self.canvas.session.get_next_id() - text = WhiteboardText(id,text_string, pos, style, pointsize, weight, color) + text = WhiteboardText(id, text_string, pos, style, pointsize, weight, color) self.texts.append(text) xml_str = "" xml_str += text.toxml("new") @@ -416,13 +417,13 @@ else: return "" def layerTakeDOM(self, xml_dom): - serial_number = xml_dom.getAttribute('serial') - if serial_number != "": self.serial_number = int(serial_number) - children = xml_dom._get_childNodes() + serial_number = xml_dom.get('serial') + if serial_number != None: self.serial_number = int(serial_number) + children = xml_dom.getchildren() for l in children: - nodename = l._get_nodeName() - action = l.getAttribute("action") - id = l.getAttribute('id') + nodename = l.tag + action = l.get("action") + id = l.get('id') try: if self.serial_number < int(id.split('-')[2]): self.serial_number = int(id.split('-')[2]) except: pass @@ -436,17 +437,17 @@ elif action == "new": if nodename == "line": try: - line_string = l.getAttribute('line_string') - upperleftx = l.getAttribute('upperleftx') - upperlefty = l.getAttribute('upperlefty') - lowerrightx = l.getAttribute('lowerrightx') - lowerrighty = l.getAttribute('lowerrighty') + line_string = l.get('line_string') + upperleftx = l.get('upperleftx') + upperlefty = l.get('upperlefty') + lowerrightx = l.get('lowerrightx') + lowerrighty = l.get('lowerrighty') upperleft = wx.Point(int(upperleftx),int(upperlefty)) lowerright = wx.Point(int(lowerrightx),int(lowerrighty)) - color = l.getAttribute('color') + color = l.get('color') if color == '#0000000': color = '#000000' - id = l.getAttribute('id') - width = int(l.getAttribute('width')) + id = l.get('id') + width = int(l.get('width')) except: line_string = upperleftx = upperlefty = lowerrightx = lowerrighty = color = 0 continue @@ -454,15 +455,15 @@ self.lines.append(line) elif nodename == "text": try: - text_string = l.getAttribute('text_string') - style = l.getAttribute('style') - pointsize = l.getAttribute('pointsize') - weight = l.getAttribute('weight') - color = l.getAttribute('color') + text_string = l.get('text_string') + style = l.get('style') + pointsize = l.get('pointsize') + weight = l.get('weight') + color = l.get('color') if color == '#0000000': color = '#000000' - id = l.getAttribute('id') - posx = l.getAttribute('posx') - posy = l.getAttribute('posy') + id = l.get('id') + posx = l.get('posx') + posy = l.get('posy') pos = wx.Point(0,0) pos.x = int(posx) pos.y = int(posy) diff -r ee890f424e16 -r d02e9197c066 orpg/mapper/whiteboard_msg.py --- a/orpg/mapper/whiteboard_msg.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/mapper/whiteboard_msg.py Sun Dec 19 22:44:36 2010 -0600 @@ -80,11 +80,11 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.init_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - item = item_msg(self.p_lock,c._get_nodeName()) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.init_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + item = item_msg(self.p_lock,c.tag) try: item.init_from_dom(c) except Exception, e: print e @@ -105,11 +105,11 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - item = item_msg(self.p_lock, c._get_nodeName()) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + item = item_msg(self.p_lock, c.tag) try: item.set_from_dom(c) except Exception, e: print e diff -r ee890f424e16 -r d02e9197c066 orpg/networking/gsclient.py --- a/orpg/networking/gsclient.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/networking/gsclient.py Sun Dec 19 22:44:36 2010 -0600 @@ -349,7 +349,9 @@ i = self.room_list.GetItemCount() if (data[2]=="1") or (data[2]=="True"): pwd="yes" else: pwd="no" - self.room_list.InsertStringItem(i,data[1]) + name = data[1].replace('&', "&") + name = name.replace('"', '"').replace(''', "'").replace("<", '<').replace(">", '>') + self.room_list.InsertStringItem(i, name) self.room_list.SetStringItem(i,1,data[3]) self.room_list.SetStringItem(i,2,pwd) self.room_list.SetItemData(i,int(data[0])) @@ -441,7 +443,9 @@ i = self.room_list.GetItemCount() if (g[2]=="True") or (g[2]=="1") : pwd="yes" else: pwd="no" - self.room_list.InsertStringItem(i, g[1]) + name = g[1].replace('&', "&") + name = name.replace('"', '"').replace(''', "'").replace("<", '<').replace(">", '>') + self.room_list.InsertStringItem(i, name) self.room_list.SetStringItem(i, 1, g[3]) self.room_list.SetStringItem(i, 2, pwd) self.room_list.SetItemData(i, int(g[0])) @@ -481,7 +485,9 @@ rooms = n.findall('room') for room in rooms: - self.rmList[address].append((room.get("id"), room.get("name"), + name = room.get('name').replace('&', "&") + name = name.replace('"', '"').replace(''', "'").replace("<", '<').replace(">", '>') + self.rmList[address].append((room.get("id"), name, room.get("pwd"), room.get("num_users"))) self.svrList.sort(server_instance_compare) @@ -568,36 +574,7 @@ name = self.texts["room_name"].GetValue() boot_pwd = self.texts["room_boot_pwd"].GetValue() minversion = self.texts["room_min_version"].GetValue() - # - # Check for & in name. We want to allow this becaus of its common use in D&D. - # - loc = name.find("&") - oldloc=0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "&" + e - oldloc = loc+1 - loc = name.find('"') - oldloc=0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + ""e;" + e - oldloc = loc+1 - loc = name.find("'") - oldloc=0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 + if self.buttons['gs_pwd'].GetValue(): pwd = self.texts["room_pwd"].GetValue() else: pwd = "" if name == "": wx.MessageBox("Invalid Name","Error"); diff -r ee890f424e16 -r d02e9197c066 orpg/networking/meta_server_lib.py --- a/orpg/networking/meta_server_lib.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/networking/meta_server_lib.py Sun Dec 19 22:44:36 2010 -0600 @@ -42,17 +42,15 @@ from threading import * from random import uniform +import urllib2 from urllib import urlopen, urlencode -from orpg.tools.orpg_log import debug +#from orpg.tools.orpg_log import debug from xml.etree.ElementTree import Element, fromstring, parse, tostring metacache_lock = RLock() -def get_server_dom(data=None,path=None, string=False): - # post data at server and get the resulting DOM - #if path == None: - # get meta server URI - # path = getMetaServerList() +def get_server_dom(data=None, path=None, string=False): + if path[len(path)-1] != "/": path += '/' # POST the data if META_DEBUG: @@ -61,10 +59,9 @@ print "==========================================" print data print - recvdata = urlopen(path, data) - etreeEl = parse(recvdata) - etreeEl = etreeEl.getroot() - data = tostring(etreeEl) + #recvdata = urllib2.Request(path, data) + response = urllib2.urlopen(path, data) + data = response.read() # Remove any leading or trailing data. This can happen on some satellite connections p = re.compile('(.*?)',re.DOTALL|re.IGNORECASE) @@ -78,7 +75,8 @@ print data print # build dom - return etreeEl + if string: return data + else: return fromstring(data) def post_server_data(name, realHostName=None): if realHostName: data = urlencode({"server_data[name]":name, @@ -136,8 +134,10 @@ #get the server's xml from the current meta bad_meta = 0 #print "Getting server list from " + meta + "..." - try: xml_dom = get_server_dom(data, meta.get('url')) - except: bad_meta = 1; print "Trouble getting servers from " + meta + "..." + try: meta_path = meta.get('url'); xml_dom = get_server_dom(data, meta_path) + except: + if meta_path == None: meta_path = 'No URL available' + bad_meta = 1; print "Trouble getting servers from " +meta_path+ "..." if bad_meta: continue node_list = xml_dom.findall('server') if len(node_list): @@ -195,8 +195,14 @@ def getMetaServerList(): # get meta server URL - url = "http://orpgmeta.appspot.com/" + meta_list = fromstring(""" + + + + """ + ) try: + component.get('validate').config_file("metaservers.xml","default_metaservers.xml") component.get('validate').config_file("settings.xml","default_settings.xml") setting = parse(dir_struct["user"]+"settings.xml") tree = setting.getroot() @@ -210,10 +216,8 @@ metas = parse(dir_struct["user"]+meta).getroot() meta_list = metas.findall('meta') return meta_list - except Exception,e: - print e - #print "using meta server URI: " + url - return url + except Exception,e: print e + return meta_list """ Beginning of Class registerThread @@ -268,6 +272,7 @@ self.destroy = 0 # Used to flag that this thread should die self.port = str(port) self.register_callback = register_callback # set a method to call to report result of register + self.IdAttempts = 0 """ This thread will communicate with one and only one Meta. If the Meta in ini.xml is changed after @@ -357,11 +362,12 @@ "act":"unregister"} ) for path in getMetaServerList(): try: # this POSTS the request and returns the result - etreeEl = get_server_dom(data, path.get('url')) - if xml_dom.get("errmsg"): - print "Error durring unregistration: " + xml_dom.get("errmsg") - except: + etreeEl = get_server_dom(data, self.path) + if etreeEl.get("errmsg") != None: + print "Error durring unregistration: " +etreeEl.get("errmsg") + except Exception, e: if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us." + if META_DEBUG: print e # If there's an error, echo it to the console # No special handling is required. If the de-registration worked we're done. If @@ -392,7 +398,10 @@ # Set the server's attibutes, if specified. if name: self.name = name - if num_users != None: self.num_users = num_users + if num_users != None: + try: self.num_users = len(num_users) + except: self.num_users = num_users + else: self.num_users = 0 if realHostName: self.realHostName = realHostName # build POST data if self.realHostName: @@ -413,33 +422,32 @@ "server_data[version]":PROTOCOL_VERSION, "server_data[num_users]":self.num_users, "act":"register"} ) - for path in getMetaServerList(): - try: # this POSTS the request and returns the result - etreeEl = get_server_dom(data, path.get('url')) - except: - if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." - if META_DEBUG: print data - if META_DEBUG: print - self.interval = 0 - """ - If we are in the registerThread thread, then setting interval to 0 - will end up causing a retry in about 6 seconds (see self.run()) - If we are in the main thread, then setting interval to 0 will do one - of two things: - 1) Do the same as if we were in the registerThread - 2) Cause the next, normally scheduled register() call to use the values - provided in this call. - - Which case occurs depends on where the registerThread thread is when - the main thread calls register(). - """ - return 0 # indicates that it was okay to call, not that no errors occurred + try: # this POSTS the request and returns the result + etreeEl = get_server_dom(data, self.path) + except Exception, e: + if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." + if META_DEBUG: print data + if META_DEBUG: print e + self.interval = 0 + """ + If we are in the registerThread thread, then setting interval to 0 + will end up causing a retry in about 6 seconds (see self.run()) + If we are in the main thread, then setting interval to 0 will do one + of two things: + 1) Do the same as if we were in the registerThread + 2) Cause the next, normally scheduled register() call to use the values + provided in this call. + + Which case occurs depends on where the registerThread thread is when + the main thread calls register(). + """ + return 0 # indicates that it was okay to call, not that no errors occurred # If there is a DOM returned .... if etreeEl != None: # If there's an error, echo it to the console - if etreeEl.get("errmsg"): - print "Error durring registration: " + etreeEl.get("errmsg") + if etreeEl.get("errmsg") != None: + print "Error durring registration at: " +self.path+ " Error: " +etreeEl.get("errmsg") if META_DEBUG: print data if META_DEBUG: print """ @@ -465,10 +473,11 @@ self.id = etreeEl.get("id") self.cookie = etreeEl.get("cookie") #if etreeEl.get("errmsg") == None: updateMetaCache(xml_dom) - except: + except Exception, e: if META_DEBUG: print if META_DEBUG: print "OOPS! Is the Meta okay? It should be returning an id, cookie, and interval." if META_DEBUG: print "Check to see what it really returned.\n" + if META_DEBUG: print e # Let xml_dom get garbage collected try: xml_dom.unlink() except: pass diff -r ee890f424e16 -r d02e9197c066 orpg/networking/mplay_client.py --- a/orpg/networking/mplay_client.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/networking/mplay_client.py Sun Dec 19 22:44:36 2010 -0600 @@ -38,8 +38,8 @@ from orpg.orpg_version import CLIENT_STRING, PROTOCOL_VERSION, VERSION from orpg.orpgCore import component -from orpg.orpg_xml import xml -from orpg.tools.orpg_log import debug +#from orpg.orpg_xml import xml +#from orpg.tools.orpg_log import debug from orpg.tools.settings import settings from xml.etree.ElementTree import ElementTree, Element, iselement @@ -81,9 +81,9 @@ STATUS_SET_URL = 1 def parseXml(data): + debug(('Developers note. Deprecated call to parseXml!!'), parents=True) "parse and return doc" - doc = xml.parseXml(data) - doc.normalize() + doc = fromstring(data) return doc def myescape(data): @@ -387,7 +387,6 @@ def __init__(self,name,callbacks): client_base.__init__(self) component.add('mp_client', self) - self.xml = component.get('xml') self.set_name(name) self.on_receive = callbacks['on_receive'] self.on_mplay_event = callbacks['on_mplay_event'] diff -r ee890f424e16 -r d02e9197c066 orpg/networking/mplay_server.py --- a/orpg/networking/mplay_server.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/networking/mplay_server.py Sun Dec 19 22:44:36 2010 -0600 @@ -51,6 +51,7 @@ from mplay_client import MPLAY_LENSIZE from orpg.dirpath import dir_struct import orpg.tools.validate +import htmlentitydefs from orpg.mapper.map_msg import * from threading import Lock, RLock @@ -60,7 +61,7 @@ from xml.etree.ElementTree import ElementTree, Element, iselement from xml.etree.ElementTree import fromstring, tostring, parse, XML -from orpg.tools.orpg_log import logger, crash, debug +from orpg.tools.orpg_log import logger#, crash, debug from orpg.tools.decorators import debugging # Snag the version number @@ -316,7 +317,7 @@ self.banDoc = self.banDom.getroot() for element in self.banDom.findall('banned'): - playerName = element.get('name').replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">") + playerName = element.get('name').replace("&", "&").replace("<", "<").replace('"', "").replace(">", ">") playerIP = element.get('ip') self.ban_list[playerIP] = {} self.ban_list[playerIP]['ip'] = playerIP @@ -336,7 +337,7 @@ etreeEl = Element('server') for ip in self.ban_list: el = Element('banned') - el.set('name', str(self.ban_list[ip]['name'].replace("&", "&").replace("<", "<").replace(""", '"').replace(">", ">"))) + el.set('name', str(self.ban_list[ip]['name'].replace("&", "&").replace("<", "<").replace("", '"').replace(">", ">"))) el.set('ip', str(self.ban_list[ip]['ip'])) etreeEl.append(el) file = open(self.userPath + self.banFile ,"w") @@ -362,9 +363,9 @@ if self.configDoc.get("admin"): self.boot_pwd = self.configDoc.get("admin") elif self.configDoc.get("boot"): self.boot_pwd = self.configDoc.get("boot") if len(self.boot_pwd) < 1: self.boot_pwd = raw_input("Enter admin password: ") - if not hasattr(self, 'reg') and self.configDoc.get("register"): + if not hasattr(self, 'reg'): self.reg = self.configDoc.get("register") - if not len(self.reg) > 0 or self.reg[0].upper() not in ("Y", "N"): + if (not len(self.reg) > 0) or (self.reg[0].upper() not in ("Y", "N")) or (self.reg == None): opt = raw_input("Do you want to post your server to the OpenRPG Meta Server list? (y,n) ") if len(opt) and (opt[0].upper() == 'Y'): self.reg = 'Y' else: self.reg = 'N' @@ -648,21 +649,40 @@ def registerRooms(self, args=None): rooms = '' - id = '0' - time.sleep(500) - for rnum in self.groups.keys(): - rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][name]":self.groups[rnum].name, - "room_data[rooms][" + str(rnum) + "][pwd]":str(self.groups[rnum].pwd != "")})+'&' - for pid in self.groups[rnum].players: - rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][players]["+str(pid)+"]":self.players[pid].name,})+'&' + serverId = '0' + x = 0 + cache = {} for meta in self.metas.keys(): - while id == '0': - id, cookie = self.metas[meta].getIdAndCookie() - data = urllib.urlencode( {"room_data[server_id]":id, - "act":'registerrooms'}) - get_server_dom(data+'&'+rooms, self.metas[meta].path, string=True) + # There is no point in wasting our planetary resources on attempting to register rooms to a meta + # that does not provide that service. When they eventually get their head out of the elitist clouds + # this work around can be removed. + if meta.get('url') != 'http://orpgmeta.appspot.com': + cache[meta] = self.metas[meta] + for meta in cache.keys(): + self.log_msg("Registering rooms too: " +meta.get('url')) + self.log_msg("Obtaining Server ID from: " +meta.get('url')) + for x in range (1, 100): + serverId, cookie = self.metas[meta].getIdAndCookie() + if serverId == '0': + self.metas[meta].IdAttempts += 100 + if self.metas[meta].IdAttempts > 1000: + self.metas[meta].unregister() + self.log_msg("Deleting Meta: " +meta.get('url')+ " after 1000 attempts.") + del self.metas[meta] + break + if serverId != '0': + self.log_msg("Obtained Server ID: " +serverId+ " from: " +meta.get('url')) + self.metas[meta].IdAttempts = 0 + for rnum in self.groups.keys(): + rooms += urllib.urlencode({"room_data[rooms][" +str(rnum)+ "][name]":self.groups[rnum].name, + "room_data[rooms][" +str(rnum)+ "][pwd]":str(self.groups[rnum].pwd != ""), + "room_data[rooms][" +str(rnum)+ "][players]":str(len(self.groups[rnum].players)) + })+'&' + data = urllib.urlencode({"room_data[server_id]":serverId, + "act":'registerrooms'}) + get_server_dom(data+'&'+rooms, meta.get('url'), string=True) - def register(self,name_given=None): + def register(self, name_given=None): if name_given == None: name = self.name else: self.name = name = name_given name = self.clean_published_servername(name) @@ -676,7 +696,6 @@ if self.show_meta_messages != 0: self.log_msg("Found these valid metas:") for meta in metalist: self.log_msg("Meta:" + meta.get('url')) - """ # Go through the list and see if there is already a running register # thread for the meta. @@ -686,26 +705,27 @@ # iterate through the currently running metas and prune any # not currently listed in the Meta Server list. """ - if self.show_meta_messages != 0: self.log_msg( "Checking running register threads for outdated metas.") for meta in self.metas.keys(): if self.show_meta_messages != 0: self.log_msg("meta:" + meta + ": ") if not meta in metalist: # if the meta entry running is not in the list if self.show_meta_messages != 0: self.log_msg( "Outdated. Unregistering and removing") self.metas[meta].unregister() + self.log_msg("Unregistering from: " +meta.get('url')) del self.metas[meta] else: if self.show_meta_messages != 0: self.log_msg( "Found in current meta list. Leaving intact.") # Now call register() for alive metas or start one if we need one for meta in metalist: - if self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive(): + self.log_msg("Registering too: " +meta.get('url')) + if (self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive()): self.metas[meta].register(name=name, realHostName=self.server_address, num_users=num_players) else: self.metas[meta] = registerThread(name=name, realHostName=self.server_address, - num_users=num_players, MetaPath=meta, port=self.server_port, + num_users=num_players, MetaPath=meta.get('url'), port=self.server_port, register_callback=self.register_callback) self.metas[meta].start() @@ -723,8 +743,9 @@ # Instead, loop through all existing meta threads and unregister them """ - for meta in self.metas.values(): - if meta and meta.isAlive(): meta.unregister() + for meta in self.metas.keys(): + self.log_msg("Unregistering from: " +meta.get('url')) + if self.metas[meta] and self.metas[meta].isAlive(): self.metas[meta].unregister() self.be_registered = 0 """ @@ -1211,11 +1232,9 @@ self.log_msg(("update_group", (self.groups[LOBBY_ID].name, LOBBY_ID, len(self.groups[LOBBY_ID].players) ) )) cmsg = ("connect", props) ################################################# self.log_msg(cmsg) - - # If already registered then re-register, thereby updating the Meta - # on the number of players - if self.be_registered: - self.register() + for meta in self.metas.keys(): + self.metas[meta].num_users = len(self.players) + thread.start_new_thread(self.registerRooms,(0,)) except: traceback.print_exc() @@ -1673,33 +1692,8 @@ # Check for & in name. We want to allow this because of its common # use in d&d games. try: - loc = name.find("&") - oldloc = 0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - value = b + "&" + e - oldloc = loc+1 - loc = name.find("'") - oldloc = 0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 - loc = name.find('"') - oldloc = 0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + """ + e - oldloc = loc+1 + name = name.replace('&', '&') + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") oldroomname = self.groups[gid].name self.groups[gid].name = str(name) lmessage = "Room name changed to from \"" + oldroomname + "\" to \"" + name + "\"" @@ -1726,34 +1720,8 @@ # Check for & in name. We want to allow this because of its common # use in d&d games. - - loc = name.find("&") - oldloc = 0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "&" + e - oldloc = loc+1 - loc = name.find("'") - oldloc = 0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 - loc = name.find('"') - oldloc = 0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + """ + e - oldloc = loc+1 + name = name.replace('&', '&') + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") group_id = str(self.next_group_id) self.next_group_id += 1 @@ -1809,14 +1777,10 @@ del self.players[id] self.log_msg(dmsg) self.log_msg(("disconnect",id)) - """ - # If already registered then re-register, thereby updating the Meta - # on the number of players - # Note: Upon server shutdown, the server is first unregistered, so - # this code won't be repeated for each player being deleted. - """ - if self.be_registered: - self.register() + self.log_msg(("update_group", (self.groups[group_id].name, group_id, len(self.groups[group_id].players) ))) + for meta in self.metas.keys(): + self.metas[meta].num_users = len(self.players) + thread.start_new_thread(self.registerRooms,(0,)) except Exception, e: self.log_msg( ('exception', str(e)) ) self.log_msg("Explicit garbage collection shows %s undeletable items." % str(gc.collect())) @@ -1825,30 +1789,32 @@ act = xml_dom.get("action") group_id = self.players[id].group_id ip = self.players[id].ip - self.log_msg("Player with IP: " + str(ip) + " joined.") ServerPlugins.setPlayer(self.players[id]) self.send_to_group(id,group_id,data) if act=="new": try: self.send_player_list(id,group_id) self.send_group_list(id) + self.log_msg("Player with IP: " + str(ip) + " connected.") except Exception, e: self.log_msg( ('exception', str(e)) ); traceback.print_exc() elif act=="del": self.del_player(id,group_id) self.check_group(id, group_id) + self.log_msg("Player with IP: " + str(ip) + " disconnected.") elif act=="update": self.players[id].take_dom(xml_dom) + self.log_msg("Player with IP: " + str(ip) + " updated.") self.log_msg(("update", {"id": id, - "name": xml_dom.get("name"), - "status": xml_dom.get("status"), - "role": xml_dom.get("role"), - "ip": str(ip), - "group": xml_dom.get("group_id"), - "room": xml_dom.get("name"), - "boot": xml_dom.get("rm_boot"), - "version": xml_dom.get("version"), - "ping": xml_dom.get("time") \ - })) + "name": xml_dom.get("name"), + "status": xml_dom.get("status"), + "role": xml_dom.get("role"), + "ip": str(ip), + "group": xml_dom.get("group_id"), + "room": xml_dom.get("name"), + "boot": xml_dom.get("rm_boot"), + "version": xml_dom.get("version"), + "ping": xml_dom.get("time") \ + })) def strip_cheat_roll(self, string): try: @@ -1988,7 +1954,7 @@ given_boot_pwd = None try: xml_dom = XML(msg) - given_boot_pwd = xml_dom.get("boot_pwd") + given_boot_pwd = xml_dom.find('boot').get("boot_pwd") except Exception, e: print "Error in parse of boot message, Ignoring." @@ -2011,31 +1977,31 @@ """ if given_boot_pwd == server_admin_pwd: # Send a message to everyone in the room, letting them know someone has been booted - boot_msg = "Booting '(%s) %s' from server..." % (from_id, group_id, to_id, self.players[to_id].name) + msg = '' + msg += 'Booting (' +str(to_id)+ ') ' +self.players[to_id].name+ ' from server...' + + boot_msg = self.buildMsg('all', '0', group_id, msg) self.log_msg("boot_msg:" + boot_msg) self.send_to_group( "0", group_id, boot_msg ) time.sleep( 1 ) self.log_msg("Booting player " + str(to_id) + " from server.") - # Send delete player event to all self.send_to_group("0",group_id,self.players[to_id].toxml("del")) - # Remove the player from local data structures self.del_player(to_id,group_id) - # Refresh the group data self.check_group(to_id, group_id) elif actual_boot_pwd == given_boot_pwd: # Send a message to everyone in the room, letting them know someone has been booted - boot_msg = "Booting '(%s) %s' from room..." % (from_id, group_id, to_id, self.players[to_id].name) + msg = '' + msg += 'Booting (' +str(to_id)+ ') ' +self.players[to_id].name+ ' from server...' + boot_msg = self.buildMsg('all', from_id, group_id, msg) self.log_msg("boot_msg:" + boot_msg) self.send_to_group( "0", group_id, boot_msg ) time.sleep( 1 ) - #dump player into the lobby self.move_player(to_id,"0") - # Refresh the group data self.check_group(to_id, group_id) else: @@ -2051,7 +2017,9 @@ finally: try: - if xml_dom: xml_dom.unlink() + try: + if xml_dom: xml_dom.unlink() + except: pass except Exception, e: traceback.print_exc() self.log_msg('Exception in xml_dom.unlink() ' + str(e)) @@ -2094,7 +2062,7 @@ configDom = parse(dir_struct["user"] + 'ban_list.xml') self.ban_list = {} for element in configDom.findall('banned'): - player = element.get('name').replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">") + player = element.get('name').replace("&", "&").replace("<", "<").replace('"', "").replace(">", ">") ip = element.get('ip') self.ban_list[ip] = {} self.ban_list[ip]['ip'] = ip diff -r ee890f424e16 -r d02e9197c066 orpg/networking/mplay_server_gui.py --- a/orpg/networking/mplay_server_gui.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/networking/mplay_server_gui.py Sun Dec 19 22:44:36 2010 -0600 @@ -348,7 +348,10 @@ chat.set('type', '1') chat.set('version', '1.0') chat.text = broadcast - msg = self.main.server.server.buildMsg('all', '0', '1', tostring(chat)) + msg = self.main.server.server.buildMsg('all', + '0', + str(self.main.server.server.players[playerID]), + tostring(chat)) if len(msg): self.main.server.server.send_to_group('0', str(groupID), msg ) elif menuItem == 6: @@ -420,6 +423,7 @@ menu = wx.Menu() menu.Append(1, 'Start', 'Start server.') menu.Append(2, 'Stop', 'Shutdown server.') + menu.Append(16, 'Clear Log', 'Empty server log') menu.AppendSeparator() menu.Append(3, 'E&xit', 'Exit application.') self.Bind(wx.EVT_MENU, self.OnStart, id=1) @@ -455,6 +459,7 @@ self.Bind(wx.EVT_MENU, self.StopPingPlayers, id=8) self.Bind(wx.EVT_MENU, self.ConfigPingInterval, id=9) self.Bind(wx.EVT_MENU, self.LogToggle, id=10) + self.Bind(wx.EVT_MENU, self.ClearLog, id=16) self.mainMenu.Append( menu, '&Configuration') # Traipse Suite of Additions. @@ -562,6 +567,9 @@ def LogToggle(self, event): self.do_log = event.IsChecked() + def ClearLog(self, event): + self.log.SetValue('') + def OnLogMessage( self, event ): self.Log( event.message ) @@ -658,19 +666,20 @@ wx.EndBusyCursor() else: self.show_error("Server is already running.", "Error Starting Server") - def OnStop(self, event = None): + def OnStop(self, event=None): """ Stop server. """ if self.STATUS == SERVER_RUNNING: - self.OnUnregister() + self.OnUnregister(event) self.server.stop() self.STATUS = SERVER_STOPPED - self.sb.SetStatusText("Stopped", 3) - self.SetTitle(__appname__ + "- (stopped) - (unregistered)") - self.mainMenu.Enable(1, True) - self.mainMenu.Enable(2, False) - self.mainMenu.Enable(4, False) - self.mainMenu.Enable(5, False) - self.conns.DeleteAllItems() + if event != 'Quit': + self.sb.SetStatusText("Stopped", 3) + self.SetTitle(__appname__ + "- (stopped) - (unregistered)") + self.mainMenu.Enable(1, True) + self.mainMenu.Enable(2, False) + self.mainMenu.Enable(4, False) + self.mainMenu.Enable(5, False) + self.conns.DeleteAllItems() def OnRegister(self, event = None): """ Call into mplay_server's register() function. @@ -695,11 +704,12 @@ """ wx.BeginBusyCursor() self.server.server.unregister() - self.sb.SetStatusText("Unregistered", 4) - self.mainMenu.Enable(5, False) - self.mainMenu.Enable(4, True) - #self.mainMenu.Enable( 2, True ) - self.SetTitle(__appname__ + "- (running) - (unregistered)") + if event != 'Quit': + self.sb.SetStatusText("Unregistered", 4) + self.mainMenu.Enable(5, False) + self.mainMenu.Enable(4, True) + #self.mainMenu.Enable( 2, True ) + self.SetTitle(__appname__ + "- (running) - (unregistered)") wx.EndBusyCursor() def ModifyBanList(self, event): @@ -726,7 +736,7 @@ def ExitConfirmed(self, event=None): """ Quit the program. """ - self.OnStop() + self.OnStop('Quit') self.BanListDialog.Destroy() wx.CallAfter(self.Destroy) diff -r ee890f424e16 -r d02e9197c066 orpg/orpg_version.py --- a/orpg/orpg_version.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/orpg_version.py Sun Dec 19 22:44:36 2010 -0600 @@ -2,9 +2,9 @@ SERVER_MIN_CLIENT_VERSION = "1.7.1" #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed) -DISTRO = "Traipse" +DISTRO = "Traipse Beta" DIS_VER = "Ornery Orc" -BUILD = "100505-00" +BUILD = "101220-00" # This version is for network capability. PROTOCOL_VERSION = "1.2" diff -r ee890f424e16 -r d02e9197c066 orpg/orpg_windows.py --- a/orpg/orpg_windows.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/orpg_windows.py Sun Dec 19 22:44:36 2010 -0600 @@ -56,49 +56,54 @@ pos = string.rfind(file_name,'.') ext = string.lower(file_name[pos+1:]) img_type = 0 - recycle_bin = {"gif": wx.BITMAP_TYPE_GIF, "jpg": wx.BITMAP_TYPE_JPEG, + recycle_bin = {"gif": wx.BITMAP_TYPE_GIF, "jpg": wx.BITMAP_TYPE_JPEG, "jpeg": wx.BITMAP_TYPE_JPEG, "bmp": wx.BITMAP_TYPE_BMP, "png": wx.BITMAP_TYPE_PNG} - if recycle_bin.has_key(ext): img_type = recycle_bin[ext] - else: img_type = None - del recycle_bin; return img_type + if recycle_bin.has_key(ext): img_type = recycle_bin[ext] + else: img_type = None + del recycle_bin; return img_type ################################ ## Tabs ################################ class orpgTabberWnd(FNB.FlatNotebook): - def __init__(self, parent, closeable=False, size=wx.DefaultSize, style = False): + def __init__(self, parent, closeable=False, size=wx.DefaultSize, style=False): nbstyle = FNB.FNB_HIDE_ON_SINGLE_TAB|FNB.FNB_BACKGROUND_GRADIENT + if style: nbstyle |= style FNB.FlatNotebook.__init__(self, parent, -1, size=size, style=nbstyle) rgbcovert = orpg.tools.rgbhex.RGBHex() self.log = component.get("log") self.log.log("Enter orpgTabberWnd", ORPG_DEBUG) self.settings = component.get("settings") - tabtheme = self.settings.get_setting('TabTheme') - tabtext = self.settings.get_setting('TabTextColor') + tabtheme = self.settings.get('TabTheme') + tabtext = self.settings.get('TabTextColor') (tred, tgreen, tblue) = rgbcovert.rgb_tuple(tabtext) - tabbedwindows = component.get("tabbedWindows") - tabbedwindows.append(self) - component.add("tabbedWindows", tabbedwindows) + component.get("tabbedWindows").append(self) theme_dict = {'slanted&aqua': FNB.FNB_VC8, 'slanted&bw': FNB.FNB_VC8, 'flat&aqua': FNB.FNB_FANCY_TABS, - 'flat&bw': FNB.FNB_FANCY_TABS, 'customflat': FNB.FNB_FANCY_TABS, 'customslant': FNB.FNB_VC8, - 'slanted&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS, 'slant&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS} - nbstyle |= theme_dict[tabtheme] - if style: nbstyle |= style - self.SetWindowStyleFlag(nbstyle) + 'flat&bw': FNB.FNB_FANCY_TABS, 'customflat': FNB.FNB_FANCY_TABS, 'customslant': FNB.FNB_VC8} + #'slanted&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS, 'slant&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS} + if theme_dict.has_key(tabtheme): style |= theme_dict[tabtheme] + else: style |= theme_dict['customflat']; self.settings.change('TabTheme', 'customflat') + self.SetWindowStyleFlag(style) + + tabbg = self.settings.get('TabBackgroundGradient') + (red, green, blue) = rgbcovert.rgb_tuple(tabbg) + self.SetTabAreaColour(wx.Color(red, green, blue)) # Tas - sirebral. Planned changes to the huge statement below. if tabtheme == 'slanted&aqua': self.SetGradientColourTo(wx.Color(0, 128, 255)) self.SetGradientColourFrom(wx.WHITE) + self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'slanted&bw': self.SetGradientColourTo(wx.WHITE) self.SetGradientColourFrom(wx.WHITE) + self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'flat&aqua': - self.SetGradientColourFrom(wx.Color(0, 128, 255)) - self.SetGradientColourTo(wx.WHITE) + self.SetGradientColourTo(wx.Color(0, 128, 255)) + self.SetGradientColourFrom(wx.WHITE) self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'flat&bw': @@ -107,28 +112,21 @@ self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'customflat': - gfrom = self.settings.get_setting('TabGradientFrom') - (red, green, blue) = rgbcovert.rgb_tuple(gfrom) - self.SetGradientColourFrom(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientTo')) + self.SetGradientColourTo(wx.Color(red, green, blue)) - gto = self.settings.get_setting('TabGradientTo') - (red, green, blue) = rgbcovert.rgb_tuple(gto) - self.SetGradientColourTo(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientFrom')) + self.SetGradientColourFrom(wx.Color(red, green, blue)) self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) elif tabtheme == 'customslant': - gfrom = self.settings.get_setting('TabGradientFrom') - (red, green, blue) = rgbcovert.rgb_tuple(gfrom) - self.SetGradientColourFrom(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientTo')) + self.SetGradientColourTo(wx.Color(red, green, blue)) - gto = self.settings.get_setting('TabGradientTo') - (red, green, blue) = rgbcovert.rgb_tuple(gto) - self.SetGradientColourTo(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientFrom')) + self.SetGradientColourFrom(wx.Color(red, green, blue)) self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) - tabbg = self.settings.get_setting('TabBackgroundGradient') - (red, green, blue) = rgbcovert.rgb_tuple(tabbg) - self.SetTabAreaColour(wx.Color(red, green, blue)) self.Refresh() self.log.log("Exit orpgTabberWnd", ORPG_DEBUG) diff -r ee890f424e16 -r d02e9197c066 orpg/orpg_xml.py --- a/orpg/orpg_xml.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/orpg_xml.py Sun Dec 19 22:44:36 2010 -0600 @@ -31,7 +31,7 @@ from orpg.tools.orpg_log import logger, debug class xml: - debug('Developers note. Deprecated call to orpg_xml!!') + debug(('Developers note. Deprecated call to orpg_xml!!'), parents=True) def __init__(self): pass diff -r ee890f424e16 -r d02e9197c066 orpg/templates/feature.xml --- a/orpg/templates/feature.xml Wed May 05 08:55:51 2010 -0500 +++ b/orpg/templates/feature.xml Sun Dec 19 22:44:36 2010 -0600 @@ -1,4 +1,4 @@ - + Welcome to Traipse OpenRPG. @@ -504,8 +504,7 @@ !=52 Card Deck::([#1d13], [#1d4])=! - - + @@ -552,7 +551,63 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -565,7 +620,11 @@ - + + + + + diff -r ee890f424e16 -r d02e9197c066 orpg/templates/nodes/4e_char_sheet.xml --- a/orpg/templates/nodes/4e_char_sheet.xml Wed May 05 08:55:51 2010 -0500 +++ b/orpg/templates/nodes/4e_char_sheet.xml Sun Dec 19 22:44:36 2010 -0600 @@ -32,27 +32,27 @@ This bears repeating: It comes with a Back Pack text node that you can clone to make bags and other containers. - - - + + + - + - - + + - + - + - + text @@ -104,7 +104,7 @@ Total !=AC Bonus::(3,2)=!+!=AC Bonus::(4,2)=! - Armor!!Armor::(2,2)!!Misc0 + Armor!=Armor::(2,2)=!Misc0 diff -r ee890f424e16 -r d02e9197c066 orpg/templates/nodes/ShapeShifter.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/templates/nodes/ShapeShifter.xml Sun Dec 19 22:44:36 2010 -0600 @@ -0,0 +1,229 @@ +What is the Shape Shifter + +The Shape Shifter node is a special node based off the 4e PC Sheet that comes with Traipse. The shape shifter uses a special feature in Traipse's Namespace 2.0 that allows it to reference nodes from inside another reference. + +How does this node work? + +The Abilities grid actually references the Shapes::Shape node to find the Shape your PC is currently in. The default is Human. Inside the Shapes container different grids for Abilities can be placed and the text inside the Shape can be changed to use a new Abilities grid. + +Using the Node: + +Using the node is simple. Just clone the 'Human' grid, modify the base ability scores, and then rename the grid to the desired shape. When you want your character to become that shape, change the text in the Shape node to the name of the desired shape. + +When making references always reference the Abilities grid as that is the one that will update with the current shape. + + + + + + + + + + + + + + + + + + + + + + + + + text + + text + + text + + text + + 1 + + 1 + + + + Weapon + Damage + + + Sword + d6 + + Maced8 + + + + + + + Armor + Bonus + + + Total + !=To Hit::3,2=! + !=To Hit::4,2=! + + BAB15Str Mod!=Abilities::(1,3)=! + + + + + + + Armor + Bonus + + + Total + !=AC Bonus::3,2=!+!=AC Bonus::4,2=! + + Armor!=Armor::2,2=!Misc0 + + + + + + + Armor + Bonus + + + Total + !=Armor::3,2=! + + Base10ArmorShield + + + + + + + Armor + Bonus + Descripton + + Total + !=Feats::3,2=! + + Feat0 + + + + + + + Str + !=!"Shape"!::1,2=! + (!=Abilities::(1,2)=!-10)/2 + + Dex + !=!"Shape"!::2,2=! + (!=Abilities::(2,2)=!-10)/2 + + Con + !=!"Shape"!::3,2=! + (!=Abilities::(3,2)=!-10)/2 + + Int + !=!"Shape"!::4,2=! + (!=Abilities::(4,2)=!-10)/2 + + Wis + !=!"Shape"!::5,2=! + (!=Abilities::(5,2)=!-10)/2 + + Cha + !=!"Shape"!::6,2=! + (!=Abilities::(6,2)=!-10)/2 + + + + + Human + + + Str + 24 + (!=!"Shape"!::(1,2)=!-10)/2 + + Dex + 24 + (!=!"Shape"!::(2,2)=!-10)/2 + + Con + 24 + (!=!"Shape"!::(3,2)=!-10)/2 + + Int + 24 + (!=!"Shape"!::(4,2)=!-10)/2 + + Wis + 24 + (!=!"Shape"!::(5,2)=!-10)/2 + + Cha + 24 + (!=!"Shape"!::(6,2)=!-10)/2 + + + + + + + + Str + 8 + (!=!"Shape"!::(1,2)=!-10)/2 + + Dex + 8 + (!=!"Shape"!::(2,2)=!-10)/2 + + Con + 8 + (!=!"Shape"!::(3,2)=!-10)/2 + + Int + 8 + (!=!"Shape"!::(4,2)=!-10)/2 + + Wis + 8 + (!=!"Shape"!::(5,2)=!-10)/2 + + Cha + 8 + (!=!"Shape"!::(6,2)=!-10)/2 + + + + + + /me uses an At Will +<b>Attack:</b> [1d20+2+!#Abilities::(2,3)#!] +<b>Damage:</b> [2!#Combat::Weapons::(2,2)#!] + + /me uses an Encounter +<b>Attack:</b> [1d20+2+!#Abilities::(2,3)#!] +<b>Damage:</b> [2!#Combat::Weapons::(2,2)#!] + + /me uses an Daily +<b>Attack:</b> [1d20+2+!#Abilities::(2,3)#!] +<b>Damage:</b> [2!#Combat::Weapons::(2,2)#!] + + Nothing + + Nothing + + Nothing + + Nothing + \ No newline at end of file diff -r ee890f424e16 -r d02e9197c066 orpg/templates/nodes/Warhammerv2CS2-Traipse.xml --- a/orpg/templates/nodes/Warhammerv2CS2-Traipse.xml Wed May 05 08:55:51 2010 -0500 +++ b/orpg/templates/nodes/Warhammerv2CS2-Traipse.xml Sun Dec 19 22:44:36 2010 -0600 @@ -1,71 +1,69 @@ - - -
- + + + - + - + - + - + - - + + 1 - + - + - + - + 1 - + - + - + - + Meduim - + - + - + - - - + + - + - + - + Copper @@ -93,227 +91,216 @@ - - - + + [1d20 + (!=Character Level=! / 2) + ((!=Ability Init=! / 2) - 5) + !=Feat Init Bonus=! + !=Misc Init Bonus=!] - + 6 - - - - + + + !=Dexterity=! - + 0 - + 0 - - - + + 6 - + 0 - + 0 - + 0 - + [!=Racial Speed Base=! + !=Armor Speed Bonus=! + !=Item Speed Bonus=! + !=Misc Speed Bonus=!] - - - + + 10 - + 10 - + 10 - + 10 - + 10 - + 10 - - - - - - - - + + + + + + + + - - - + + 10 - + 10 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + 0 - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + 0 - - - - - + + + Maximum Health @@ -360,7 +347,7 @@ - + Armor Class @@ -384,694 +371,652 @@ - - [1d20 + !=Class Save Bonus=! + !=Racial Save Bonus=! + !=Feat Save Bonus=! + !=Misc Save Bonus=!] + + [1d20 + !=Class Save Bonus=! + !=Racial Save Bonus=! + !=Feat Save Bonus=! + !=Misc Save Bonus=!] - - - - + + + 0 - + 0 - + 0 - + 0 - - - + + 0 - + !=Dexterity=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=AC Ability=! / 2) - 5) + !=Class AC Bonus=! + !=Feat AC Bonus=! + !=Equipment AC Bonus=! + !=Misc AC Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=AC Ability=! / 2) - 5) + !=Class AC Bonus=! + !=Feat AC Bonus=! + !=Equipment AC Bonus=! + !=Misc AC Bonus=!] - - - + + 0 - + !=Strength=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Fort Ability=! / 2) - 5) + !=Class Fort Bonus=! + !=Feat Fort Bonus=! + !=Equipment Fort Bonus=! + !=Misc Fort Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Fort Ability=! / 2) - 5) + !=Class Fort Bonus=! + !=Feat Fort Bonus=! + !=Equipment Fort Bonus=! + !=Misc Fort Bonus=!] - - - + + 0 - + !=Dexterity=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Ref Ability=! / 2) - 5) + !=Class Ref Bonus=! + !=Feat Ref Bonus=! + !=Equipment Ref Bonus=! + !=Misc Ref Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Ref Ability=! / 2) - 5) + !=Class Ref Bonus=! + !=Feat Ref Bonus=! + !=Equipment Ref Bonus=! + !=Misc Ref Bonus=!] - - - + + 0 - + !=Wisdom=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Will Ability=! / 2) - 5) + !=Class Will Bonus=! + !=Feat Will Bonus=! + !=Equipment Will Bonus=! + !=Misc Will Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Will Ability=! / 2) - 5) + !=Class Will Bonus=! + !=Feat Will Bonus=! + !=Equipment Will Bonus=! + !=Misc Will Bonus=!] - - - - + + + Weapon 1 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Melee Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] - - + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Melee Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Range Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] - - + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Range Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Charge Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=! + !=Weapon 1 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Charge Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=! + !=Weapon 1 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] - - - + + Weapon 2 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Melee Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] - - + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Melee Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Range Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] - - + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Range Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Charge Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=! + !=Weapon 2 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Charge Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=! + !=Weapon 2 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] - - - + + Weapon 3 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Melee Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] - - + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Melee Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Range Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] - - + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Range Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Charge Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=! + !=Weapon 3 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Charge Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=! + !=Weapon 3 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] - - - + + Weapon 4 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Melee Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] - - + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Melee Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Range Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] - - + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Range Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Charge Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=! + !=Weapon 4 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Charge Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=! + !=Weapon 4 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] - - - + + Weapon 5 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Melee Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] - - + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Melee Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Range Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] - - + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Range Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Charge Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=! + !=Weapon 5 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Charge Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=! + !=Weapon 5 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] - - - - - - - 0 - - - 0 - - + + + + + 0 + + + 0 + + 0 - - - - + + + !=Strength=! - - 0 - - - Bull Rush: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Rush Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Rush Attack Bonus=!] + + 0 + + + Bull Rush: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Rush Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Rush Attack Bonus=!] - - - + + !=Strength=! - - 0 - - - Grab: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Grab Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Grab Attack Bonus=!] + + 0 + + + Grab: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Grab Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Grab Attack Bonus=!] - - - + + !=Strength=! - - 0 - - + + 0 + + Fortitude - - Escape: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Escape Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Escape Attack Bonus=!] vs. !=Unarmed Escape Target Defense=! + + Escape: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Escape Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Escape Attack Bonus=!] vs. !=Unarmed Escape Target Defense=! - - - - - + + + 1 - + Power Name @@ -1138,7 +1083,7 @@ - + Power Name @@ -1195,7 +1140,7 @@ - + Power Name @@ -1263,4914 +1208,5387 @@ - - - - - + + + + At-Will 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - - - + + At-Will 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - - - + + At-Will 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - - - + + At-Will 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - - - + + At-Will 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - - - + + At-Will 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - - - + + At-Will 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - - - + + At-Will 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - - - + + At-Will 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - - - - + + + Encounter 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - - - + + Encounter 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - - - + + Encounter 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - - - + + Encounter 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - - - + + Encounter 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - - - + + Encounter 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - - - + + Encounter 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - - - + + Encounter 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - - - + + Encounter 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - - - - - + + + Daily 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - - - + + Daily 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - - - + + Daily 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - - - + + Daily 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - - - + + Daily 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - - - + + Daily 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - - - + + Daily 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - - - + + Daily 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - - - + + Daily 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - - - - - + + + Utility 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! - - - + + Utility 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + + !=Strength=! + + + 0 + + !=Strength=! - - 0 - - - !=Strength=! - - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! - - - + + Utility 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! - - - + + Utility 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! - - - + + Utility 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! - - - + + Utility 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! - - - + + Utility 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! - - - + + Utility 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! - - - + + Utility 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! - - - - + + - + - + - + @@ -6266,9 +6684,8 @@ - - - + + Player Name @@ -6315,7 +6732,7 @@ - + Maximum Health @@ -6370,7 +6787,7 @@ - + @@ -6393,7 +6810,7 @@ - + 10 @@ -6470,7 +6887,7 @@ - + 10 @@ -6484,7 +6901,7 @@ - + 0 @@ -6492,7 +6909,7 @@ - + 0 @@ -6500,7 +6917,7 @@ - + 0 @@ -6508,7 +6925,7 @@ - + 0 @@ -6518,71 +6935,69 @@ - - - - + + + Attack 1 Name - + 0 - - !=Attack 1 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 1 Bonus=!] + + !=Attack 1 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 1 Bonus=!] - + !=Strength=! - + 0 - + 1 - + 4 - + 0 - - !=Attack 1 Name=!: [Q(!=Attack 1 Damage Dice Count=!d!=Attack 1 Damage Dice Sides=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] + + !=Attack 1 Name=!: [Q(!=Attack 1 Damage Dice Count=!d!=Attack 1 Damage Dice Sides=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] - - !=Attack 1 Name=! = [Q(!=Attack 1 Damage Dice Count=!*!=Attack 1 Damage Dice Sides=!) + (!=Attack 1 Critical Extra Damage=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] + + !=Attack 1 Name=! = [Q(!=Attack 1 Damage Dice Count=!*!=Attack 1 Damage Dice Sides=!) + (!=Attack 1 Critical Extra Damage=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] - - - + + Attack 2 Name - + 0 - - !=Attack 2 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 2 Bonus=!] + + !=Attack 2 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 2 Bonus=!] - + !=Strength=! - + 0 - + 1 - + 4 - + 0 - - !=Attack 2 Name=!: [Q(!=Attack 2 Damage Dice Count=!d!=Attack 2 Damage Dice Sides=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] + + !=Attack 2 Name=!: [Q(!=Attack 2 Damage Dice Count=!d!=Attack 2 Damage Dice Sides=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] - - !=Attack 2 Name=! = [Q(!=Attack 2 Damage Dice Count=!*!=Attack 2 Damage Dice Sides=!) + (!=Attack 2 Critical Extra Damage=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] + + !=Attack 2 Name=! = [Q(!=Attack 2 Damage Dice Count=!*!=Attack 2 Damage Dice Sides=!) + (!=Attack 2 Critical Extra Damage=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] diff -r ee890f424e16 -r d02e9197c066 orpg/templates/nodes/ironclaw-guide.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/templates/nodes/ironclaw-guide.xml Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/templates/nodes/ironclaw.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/templates/nodes/ironclaw.xml Sun Dec 19 22:44:36 2010 -0600 @@ -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 ee890f424e16 -r d02e9197c066 orpg/tools/FlatNotebook.py --- a/orpg/tools/FlatNotebook.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/FlatNotebook.py Sun Dec 19 22:44:36 2010 -0600 @@ -74,6 +74,7 @@ # Beginning Of FLATNOTEBOOK wxPython Code #---------------------------------------------------------------------- +print 'Flatnotebook' import wx import random import math diff -r ee890f424e16 -r d02e9197c066 orpg/tools/InterParse.py --- a/orpg/tools/InterParse.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/InterParse.py Sun Dec 19 22:44:36 2010 -0600 @@ -44,15 +44,16 @@ tab.set_colors() tab.Post(s, send, myself) - def ParseLogic(self, s, node): + def ParseLogic(self, s, node=None): 'Nodes now parse through ParsLogic. Easily add new parse rules right here!!' - s = self.NameSpaceE(s) + if not node: s = self.NameSpaceE(s) s = self.NameSpaceI(s, node) - s = self.NodeMap(s, node) - s = self.NodeParent(s, node.get('map')) + #s = self.NodeMap(s, node) + #s = self.NodeParent(s, node) return s - def Normalize(self, s, tab): + def Normalize(self, s, tab=False): + if not tab: tab = component.get('chat') for plugin_fname in tab.activeplugins.keys(): plugin = tab.activeplugins[plugin_fname] try: s = plugin.pre_parse(s) @@ -158,19 +159,53 @@ anyone. Using !" :: "! will allow you to use an internal namespace from within another internal namespace -- TaS, Prof. Ebral""" reg2 = re.compile("(!=(.*?)=!)") - matches = reg1.findall(s) + reg2.findall(s) - tree_map = node.get('map') + """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 != :: =! + for Internal. See above Easter Egg for reasoning.""" + reg3 = re.compile("(!!(.*?)!!)") + reg4 = re.compile("(!#(.*?)#!)") + matches = reg1.findall(s) + reg2.findall(s) + reg3.findall(s) + reg4.findall(s) + try: tree_map = node.get('map') + except: return node for i in xrange(0,len(matches)): ## Build the new tree_map new_map = tree_map.split('::') + if new_map == ['']: new_map = [node.get('name')] find = matches[i][1].split('::') ## Backwards Reference the Parent Children node = self.get_node(new_map) newstr = self.LocationCheck(node, tree_map, new_map, find) s = s.replace(matches[i][0], newstr, 1) - s = self.ParseLogic(s, node) + s = s.replace(u'\xa0', ' ') + s = self.NameSpaceI(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) @@ -204,6 +239,7 @@ else: break if not newstr: newstr = 'Invalid Reference!' s = s.replace(matches[i][0], newstr, 1) + s = s.replace(u'\xa0', ' ') #Required for XSLT sheets s = self.ParseLogic(s, node) return s @@ -224,15 +260,18 @@ matches = reg.findall(s) for i in xrange(0,len(matches)): tree_map = node.get('map') - tree_map = tree_map + '::' + matches[i][1] - newstr = '!@'+ tree_map +'@!' + tree_map = str(tree_map + '::' + matches[i][1]) + if tree_map[:2] == '::': tree_map = tree_map[2:] + newstr = '!@'+ str(tree_map) +'@!' s = s.replace(matches[i][0], newstr, 1) s = self.Node(s) - s = self.NodeParent(s, tree_map) + s = self.NodeParent(s, node) return s - def NodeParent(self, s, tree_map): + def NodeParent(self, s, node): """Parses player input for embedded nodes rolls""" + if node == 'Invalid Reference!': return node + tree_map = node.get('map') cur_loc = 0 reg = re.compile("(!#(.*?)#!)") matches = reg.findall(s) diff -r ee890f424e16 -r d02e9197c066 orpg/tools/aliaslib.py --- a/orpg/tools/aliaslib.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/aliaslib.py Sun Dec 19 22:44:36 2010 -0600 @@ -473,21 +473,25 @@ filters = xml_dom.findall("filter") flist = [] self.regExList = [] - for filter in filters: - flist.append(filter.get("name")) - rules = filter.findall("rule") + for f in filters: + flist.append(f.get("name")) + rules = f.findall("rule") sub = [] - for rule in rules: sub.append([self.MakeSafeHTML(rule.get("match")), + for rule in rules: + sub.append([self.MakeSafeHTML(rule.get("match")), self.MakeSafeHTML(rule.get("sub"))]) self.regExList.append(sub) self.filterList = flist self.alias = 0 self.filter = 0 - def MakeSafeHTML(self, str): - return str.replace("&", "&").replace("<", "<").replace(""", '"').replace(">", ">").replace("'", "'") - def MakeHTMLSafe(self, str): - return str.replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">").replace("'", "'") + def MakeSafeHTML(self, s): + if s == None: return '' + return s.replace("&", "&").replace("<", "<").replace(""", '"').replace(">", ">").replace("'", "'") + + def MakeHTMLSafe(self, s): + return s.replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">").replace("'", "'") + def ImportFromTree(self, xml_dom): oldfilename = self.filename if xml_dom.get('name') == 'Alias Library': diff -r ee890f424e16 -r d02e9197c066 orpg/tools/orpg_settings.py --- a/orpg/tools/orpg_settings.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/orpg_settings.py Sun Dec 19 22:44:36 2010 -0600 @@ -33,7 +33,8 @@ from orpg.tools.orpg_log import logger from orpg.tools.validate import validate -from orpg.orpg_xml import xml +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring from orpg.tools.settings import settings class orpgSettingsWnd(wx.Dialog): @@ -70,29 +71,28 @@ def build_gui(self): validate.config_file("settings.xml","default_settings.xml") filename = dir_struct["user"] + "settings.xml" - temp_file = open(filename) - temp_file.close() - children = self.settings.xml_dom._get_childNodes() - for c in children: self.build_window(c,self.tabber) + temp_file = parse(filename) + children = self.settings.xml_dom.getchildren() + for c in children: self.build_window(c, self.tabber) def build_window(self, xml_dom, parent_wnd): - name = xml_dom._get_nodeName() + name = xml_dom.tag #container = 0 if name=="tab": temp_wnd = self.do_tab_window(xml_dom,parent_wnd) return temp_wnd def do_tab_window(self, xml_dom, parent_wnd): - type = xml_dom.getAttribute("type") - name = xml_dom.getAttribute("name") + type = xml_dom.get("type") + name = xml_dom.get("name") if type == "grid": temp_wnd = self.do_grid_tab(xml_dom, parent_wnd) parent_wnd.AddPage(temp_wnd, name, False) elif type == "tab": temp_wnd = orpgTabberWnd(parent_wnd, style=FNB.FNB_NO_X_BUTTON) - children = xml_dom._get_childNodes() + children = xml_dom.getchildren() for c in children: - if c._get_nodeName() == "tab": self.do_tab_window(c, temp_wnd) + if c.tag == "tab": self.do_tab_window(c, temp_wnd) temp_wnd.SetSelection(0) parent_wnd.AddPage(temp_wnd, name, False) elif type == "text": @@ -103,12 +103,12 @@ def do_grid_tab(self, xml_dom, parent_wnd): settings = [] - children = xml_dom._get_childNodes() + children = xml_dom.getchildren() for c in children: - name = c._get_nodeName() - value = c.getAttribute("value") - help = c.getAttribute("help") - options = c.getAttribute("options") + name = c.tag + value = c.get("value") + help = c.get("help") + options = c.get("options") settings.append([name, value, options, help]) temp_wnd = settings_grid(parent_wnd, settings, self.changes) return temp_wnd @@ -309,4 +309,3 @@ for i in range(0,cols): self.SetColSize(i,col_w) self.Refresh() -#settings = orpg.tools.settings.Settings() diff -r ee890f424e16 -r d02e9197c066 orpg/tools/scriptkit.py --- a/orpg/tools/scriptkit.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/scriptkit.py Sun Dec 19 22:44:36 2010 -0600 @@ -30,7 +30,7 @@ import time from orpg.orpg_windows import * -from orpg.orpg_xml import * +#from orpg.orpg_xml import * from orpg.orpg_wx import * import orpg.chat.chat_msg @@ -45,7 +45,7 @@ self.map = component.get( 'map' ) self.settings = component.get( 'settings' ) self.session = component.get('session') - self.xml = component.get('xml') + #self.xml = component.get('xml') def addMiniatureToMap( self, min_label, min_url, unique=0 ): """Adds a new miniature icon to the map. Miniature will be labeled unless autolabel is diff -r ee890f424e16 -r d02e9197c066 orpg/tools/settings.py --- a/orpg/tools/settings.py Wed May 05 08:55:51 2010 -0500 +++ b/orpg/tools/settings.py Sun Dec 19 22:44:36 2010 -0600 @@ -2,41 +2,32 @@ from orpg.tools.orpg_log import logger from orpg.tools.validate import validate -from orpg.orpg_xml import xml +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring from orpg.orpgCore import component from orpg.dirpath import dir_struct class Settings: def __init__(self): - self.xml = component.get("xml") self.changes = [] validate.config_file("settings.xml","default_settings.xml") self.filename = dir_struct["user"] + "settings.xml" - temp_file = open(self.filename) - txt = temp_file.read() - temp_file.close() - - self.xml_dom = xml.parseXml(txt) - - if self.xml_dom is None: self.rebuildSettings() - self.xml_dom = self.xml_dom._get_documentElement() + xml_dom = parse(dir_struct["user"] + "settings.xml") + if xml_dom == None: self.rebuildSettings() + else: self.xml_dom = xml_dom.getroot() def rebuildSettings(self): logger.info("Settings file has be corrupted, rebuilding settings.", True) try: os.remove(self.filename) except: pass - validate.config_file("settings.xml","default_settings.xml") - temp_file = open(self.filename) - txt = temp_file.read() - temp_file.close() - self.xml_dom = xml.parseXml(txt) + self.xml_dom = parse(self.filename).getroot() def get_setting(self, name): ##Depricated return self.get(name) def get(self, name): - try: return self.xml_dom.getElementsByTagName(name)[0].getAttribute("value") + try: return self.xml_dom.getiterator(name)[0].get("value") except: return 0 def get_setting_keys(self): ##Depricated @@ -44,30 +35,30 @@ def get_keys(self): keys = [] - tabs = self.xml_dom.getElementsByTagName("tab") + tabs = self.xml_dom.getiterator("tab") for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("type") == 'grid': - children = tabs[i]._get_childNodes() - for c in children: keys.append(c._get_tagName()) + if tabs[i].get("type") == 'grid': + children = tabs[i].getchildren() + for c in children: keys.append(c.tag) return keys def set_setting(self, name, value): ##Depricated self.change(name, value) def change(self, name, value): - self.xml_dom.getElementsByTagName(name)[0].setAttribute("value", value) + self.xml_dom.getiterator(name)[0].set("value", value) def add_setting(self, tab, setting, value, options, help): ##Depricated return self.add(tab, setting, value, options, help) def add(self, tab, setting, value, options, help): - if len(self.xml_dom.getElementsByTagName(setting)) > 0: return False - tabs = self.xml_dom.getElementsByTagName("tab") - newsetting = xml.parseXml('<' + setting + ' value="' + value + '" options="' + - options + '" help="' + help + '" />')._get_documentElement() + if len(self.xml_dom.getiterator(setting)) > 0: return False + tabs = self.xml_dom.getiterator("tab") + newsetting = fromstring('<' + setting + ' value="' + value + '" options="' + + options + '" help="' + help + '" />') for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("name") == tab and tabs[i].getAttribute("type") == 'grid': - tabs[i].appendChild(newsetting) + if tabs[i].get("name") == tab and tabs[i].get("type") == 'grid': + tabs[i].append(newsetting) return True return False @@ -75,49 +66,44 @@ tab_xml = '' else: tab_xml += 'name="' + tabname + '" type="' + tabtype + '">' - newtab = xml.parseXml(tab_xml)._get_documentElement() + newtab = fromstring(tab_xml) if parent != None: - tabs = self.xml_dom.getElementsByTagName("tab") + tabs = self.xml_dom.getiterator("tab") for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("name") == parent and tabs[i].getAttribute("type") == 'tab': - children = tabs[i]._get_childNodes() + if tabs[i].get("name") == parent and tabs[i].get("type") == 'tab': + children = tabs[i].getchildren() for c in children: - if c.getAttribute("name") == tabname: return False - tabs[i].appendChild(newtab) + if c.get("name") == tabname: return False + tabs[i].append(newtab) return True else: - children = self.xml_dom._get_childNodes() + children = self.xml_dom.getchildren() for c in children: - if c.getAttribute("name") == tabname: return False - self.xml_dom.appendChild(newtab) + if c.get("name") == tabname: return False + self.xml_dom.append(newtab) return True return False def updateIni(self): defaultFile = orpg.dirpath.dir_struct['template'] + 'default_settings.xml' - temp_file = open(defaultFile) - txt = temp_file.read() - temp_file.close() - default_dom = xml.parseXml(txt)._get_documentElement() - for child in default_dom.getChildren(): - if child._get_tagName() == 'tab' and child.hasChildNodes(): self.proccessChildren(child) - default_dom.unlink() + default_dom = parse(defaultfile) + for child in default_dom.getchildren(): + if child.tag == 'tab': self.proccessChildren(child) def proccessChildren(self, dom, parent=None): - if dom._get_tagName() == 'tab': - self.add_tab(parent, dom.getAttribute("name"), dom.getAttribute("type")) + if dom.tag == 'tab': self.add_tab(parent, dom.get("name"), dom.get("type")) - for child in dom.getChildren(): - if child._get_tagName() == 'tab' and child.hasChildNodes(): - self.proccessChildren(child, dom.getAttribute("name")) + for child in dom.getchildren(): + if child.tag == 'tab': self.proccessChildren(child, dom.get("name")) else: - self.add_setting(dom.getAttribute("name"), child._get_tagName(), - child.getAttribute("value"), child.getAttribute("options"), - child.getAttribute("help")) + self.add_setting(dom.get("name"), child.tag, + child.get("value"), child.get("options"), + child.get("help")) def save(self): + #self.xml_dom.write(self.filename) temp_file = open(self.filename, "w") - temp_file.write(xml.toxml(self.xml_dom,1)) + temp_file.write(tostring(self.xml_dom)) temp_file.close() settings = Settings() diff -r ee890f424e16 -r d02e9197c066 plugins/xxhiddendice.py --- a/plugins/xxhiddendice.py Wed May 05 08:55:51 2010 -0500 +++ b/plugins/xxhiddendice.py Sun Dec 19 22:44:36 2010 -0600 @@ -1,6 +1,8 @@ import os, re, wx import orpg.pluginhandler from orpg.tools.InterParse import Parse +from orpg.dieroller.base import die_rollers +from orpg.dieroller.utils import roller_manager class Plugin(orpg.pluginhandler.PluginHandler): # Initialization subroutine. @@ -21,7 +23,7 @@ #You can set variables below here. Always set them to a blank value in this section. Use plugin_enabled #to set their proper values. self.hiddenrolls = [] - self.dicere = "\{([0-9]*d[0-9]*.+)\}" + #self.dicere = "\{([0-9]*d[0-9]*.+)\}" def plugin_menu(self): self.menu = wx.Menu() @@ -40,12 +42,18 @@ def pre_parse(self, text): if self.toggle.IsChecked() == True: - m = re.search(self.dicere, text) + ## Changes added for non standard dice rolls. Prof.Ebral (TaS) + math = '[\(0-9\/\*\-\+\)]+' + dicere = '\{('+math+'d\s*([0-9]+|'+math+'|[fF]))\}' + m = re.search(dicere, text) + if m is None: + dicere = '\{('+die_rollers._rollers[roller_manager().getRoller()].regExpression+')\}' + m = re.search(dicere, text) while m: roll = "[" + m.group(1) + "]" self.hiddenrolls += [Parse.Dice(roll)] text = text[:m.start()] + "(hidden roll)" + text[m.end():] - m = re.search(self.dicere, text) + m = re.search(dicere, text) return text def post_msg(self, text, myself): diff -r ee890f424e16 -r d02e9197c066 plugins/xxooc.py --- a/plugins/xxooc.py Wed May 05 08:55:51 2010 -0500 +++ b/plugins/xxooc.py Sun Dec 19 22:44:36 2010 -0600 @@ -1,4 +1,4 @@ -import os +from orpg.tools.InterParse import Parse import orpg.pluginhandler class Plugin(orpg.pluginhandler.PluginHandler): @@ -8,7 +8,6 @@ # !chat : instance of the chat window to write to def __init__(self, plugindb, parent): orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent) - # The Following code should be edited to contain the proper information self.name = 'OOC Comments Tool' self.author = 'mDuo13' @@ -17,16 +16,14 @@ def plugin_enabled(self): #This is where you set any variables that need to be initalized when your plugin starts - self.plugin_addcommand('/ooc', self.on_ooc, 'message - This puts (( message )) to let other players know you are talking out of character') def plugin_disabled(self): #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin #such as closing windows created by the plugin - self.plugin_removecmd('/ooc') def on_ooc(self, cmdargs): #this is just an example function for a command you create create your own - self.chat.ParsePost('(( ' + cmdargs + ' ))', 1, 1) + Parse.Post('(( ' + cmdargs + ' ))', False, True, True) diff -r ee890f424e16 -r d02e9197c066 plugins/xxstdnamespace.py --- a/plugins/xxstdnamespace.py Wed May 05 08:55:51 2010 -0500 +++ b/plugins/xxstdnamespace.py Sun Dec 19 22:44:36 2010 -0600 @@ -21,15 +21,11 @@ self.help += 'is not calculated when using the Standard syntax. References must ' self.help += 'have a unique name.' - self.NameSpaceE = Parse.NameSpaceE - self.parseMethods = {'Traipse': self.NameSpaceE, 'Standard': self.NameSpaceS} + self.parseMethods = {'Traipse': Parse.NameSpaceE, 'Standard': self.NameSpaceS} def NameSpaceS(self, s): ## Re define NameSpace External - reg1 = re.compile("(!@(.*?)@!)") ## Include 'Standard' method + reg1 = re.compile("(!@(.*?)@!)") ## Inlcude 'Standard' method reg2 = re.compile("(!&(.*?)&!)") - ## Before anyone rags on me about how this is a useless plugin, or that two methods are confusing, - ## consider that this will be fully integrated later. Then consider that you can now create a reference - ## with a reference. !@ :: !& :: &! :: @! matches = reg1.findall(s) + reg2.findall(s) newstr = False nodeable = ['rpg_grid_handler', 'container_handler', @@ -40,7 +36,7 @@ node = component.get('tree').xml_root if not iselement(node): s = s.replace(matches[i][0], 'Invalid Reference!', 1); - s = self.NameSpaceS(s) + s = Parse.NameSpaceE(s) return s for x in xrange(0, len(find)): namespace = node.getiterator('nodehandler') @@ -48,7 +44,7 @@ if find[x] == node.get('name'): if node.get('class') not in nodeable: continue if node.get('class') == 'rpg_grid_handler': - try: newstr = Parse.NameSpaceGrid(find[x+1], node); break + try: newstr = self.NameSpaceGrid(find[x+1], node); break except: newstr = 'Invalid Grid Reference!' try: if Parse.FutureCheck(node, find[x+1]): break diff -r ee890f424e16 -r d02e9197c066 upmana/updatemana.py --- a/upmana/updatemana.py Wed May 05 08:55:51 2010 -0500 +++ b/upmana/updatemana.py Sun Dec 19 22:44:36 2010 -0600 @@ -1,3 +1,4 @@ +from __future__ import with_statement import wx, sys, os #just .sep maybe from manifest import manifest import shutil @@ -129,6 +130,21 @@ else: manifest.SetString("updatemana", "no_update", "off") def Update(self, evt=None): + with open(sys.path[2]+os.sep+'location.py', 'rb') as f: old_location = f.read() + ## This new location file update allows for a more portable way to start Traipse. It's aimed at Linux users. + new_location = """import sys +import os + +dyn_dir = 'System' +_home = sys.path[0] +_userbase_dir = _home + os.sep + dyn_dir +sys.path.append(_userbase_dir) +try: os.chdir(_userbase_dir) +except: print 'Failed to find ' + _userbase_dir + '\\nHopefuly you are running setup.py which would make this error normal.'""" + + if new_location != old_location: + with open(sys.path[2]+os.sep+'location.py', 'w') as f: f.write(new_location) + self.ui = ui.ui() self.repo = hg.repository(self.ui, ".") self.c = self.repo.changectx('tip') @@ -160,7 +176,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def Finish(self, evt=None): @@ -194,7 +210,7 @@ for t in types: self.btnName = str(t) self.btn[self.id] = wx.RadioButton(dlg, wx.ID_ANY, str(t), name=self.btnName) - if self.btnName == self.current: self.btn[self.id].SetValue(True) + if self.btnName == self.current: self.btn[self.id].SetValue(True); self.current_id = self.id self.btnlist[self.id] = self.btnName dlgsizer.Add(self.btn[self.id], (row, col)) col += 1; self.id += 1 @@ -212,7 +228,16 @@ def PackageSet(self, event): for btn in self.btn: - if self.btn[btn].GetValue() == True: self.current = self.btnlist[btn] + if self.btn[btn].GetValue() == True: + if self.btnlist[btn] == 'pious-paladin': + try: from PyQt4 import QtCore + except: + error = "'Pious Paladin' requires PyQt 4.6. For stability you will not be able to update." + dlg = wx.MessageDialog(None, error, 'Failed PyQt Test', wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + self.btn[self.current_id].SetValue(True) + self.current = self.btnlist[self.current_id] + else: self.current = self.btnlist[btn] branches = self.repo.branchtags() heads = dict.fromkeys(self.repo.heads(), 1) @@ -622,7 +647,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def get_packages(self, type=None): @@ -818,7 +843,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def OnExit(self):
LabelImageURLUnique