Mercurial > traipse
diff orpg/gametree/nodehandlers/dnd3e.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | 265b987cce4f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/gametree/nodehandlers/dnd3e.py Tue Jul 14 16:41:58 2009 -0500 @@ -0,0 +1,3473 @@ +# Copyright (C) 2000-2001 The OpenRPG Project +# +# openrpg-dev@lists.sourceforge.net +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# -- +# +# File: dnd3e.py +# Author: Chris Davis & Digitalxero +# Maintainer: leadb +# Version: +# $Id: dnd3e.py,v 1.33 2006/11/04 21:24:21 digitalxero Exp $ +# +# Description: The file contains code for the dnd3e nodehanlers +# +# qpatch by lead.b. All modified lines denoted by # 1.500x[or] as below +# 1.5001r fix for unable to update misc modifier for saves +# 1.5002r fix for dnd_globals not scoping 1 character's data from another -or +# causing abends or other problems due to lack of intialization from +# char abilities. getCharacterProp function added. +# This includes fix for "total on saves", making "rclick" on skill +# work to send roll to window,"total on skill rolls", +# 1.5004r getting ac mod for +# those skill which have armour class adjustments was broken. +# 1.5005r perhaps no lines marked. Under dnd3eattacks, the misc. value for +# both Melee and Ranged do not get re-displayed if the panel is closed +# and re-opened, tho the adjustment still seems to be in total... perhap +# total just isn't getting recalculated? +# 1.5006r on rclick on a weapon, on first attack roll is generated, additional +# crash,terminating the sequence. +# 1.5008r extended bonuses for "extra" attacks don't include all items. +# 1.5009r while 1.5008 is "resolved", not sure it is correct for special monk +# attacks. I'm pretty sure I fixed this. +# 1.5014r powerpoints are broken. +# 1.5017r if you bring up the entire character in edit mode (dlclick on +# top node of character), and click +# "Money and Inventory" tab, then change the amount of "plat" a +# character has, the name on the tree will be updated to match +# the "plat" entry. +# 1.5019r if str bonus was 0, forgot + for aStrengthMod. +# ---v 1.6 cut. above corrected by 1.6. +# -- items marked 1.5xxx were found prior 1.6 but not added (enhancements) +# or corrected (bugs, default if not stated) at that cut point +# 1.5003r this is currently just a "this is busted" flag, this is an rclick on +# on the saves node (above the fort/wil/ref saves) itself. It throws an +# error message into the python window, then nothing... Not even sure what +# it is -supposed- to do. set to do nothing, which I think is fine. +# 1.5011r enhancement. Damage for thrown weapon should get str adder. +# Don't think this is accounted for. Remember, JUST damage, not to-hit. +# included into 1.6002, marking resolved to simplify list. +# 1.5012r enhancement. str penalty to dam for bow/slings should be applied. +# but it's not. Remember, this is just for damage, not to-hit. +# 1.5015r if you bring up the entire character in edit mode (dlclick on +# top node of character), and click +# "Spells and Powers" tab, then "Psionic Powers", push the "Refresh +# Powers" button, the powers are refreshed but if you select the +# "PowerPoints" tab, the update is not reflected there. Must close +# and reopen edit session for refresh. (Already corrected misspelling of +# "Pionic" -> "Psionic") +# 1.6000r eliminate misc debug items, include things like getCharacterProp which +# never got used. Documenting for completeness. Minor changes for clarity +# 1.6001r bug, melee weapons, such as dagger, which have a range are currently +# being treated simply as ranged weapons... this mean dex bonuses +# are being applied for to-hit Vs strength. Melee thrown are treated +# different than ranged. +# 1.6003r bug, if double weapon handle damage specified as 1d8/1d6 as 1d8 +# for single weapon usage. The correct usage for double weapon will +# for short term at least remove requirement to have to update +# memorized list. - med priority +# 1.6008r C:\Program Files\openrpg1\orpg\templates\nodes\dnd3e.xml minor +# typos corrected, added comment on psionics. Remember to replace! +# 1.6009r tohtml fails, thus send to chat fails and pretty print fails. +# 1.6010r tohtml for power points needs some clean up. +# 1.6011r if multiple weapons are chosen for deletion from character inventory, +# at least one wrong weapons will be deleted. +# 1.6012r flurry attack negative only applied to med monk, applies to all. +# 1.6013r penalties on stats on tohtml showed +-3, instead of just -3. +# 1.6014r rclick on "Skills" node above actual skills throws an error msg to +# python window. +# 1.6015r rclick on "Attacks" or "Abilities Score" node throws an error msg to +# python window. +# 1.6016r enhancement add comment to rclick footnotes to get footnote details. +# 1.6018r resolve saves not updating on panel if open when ability scores change +# change +# 1.6021r didn't roll extra monk attacks if base to it bonus was 0. +# 1.6022r monks always got d20 damage, reversed order of checks to fix. +# v1.8 cut. +# -- items marked 1.6xxx were found prior 1.8 but not added (enhancements) +# or corrected (bugs, default if not stated) at that cut point +# 1.5007o enhancement. str bows not accounted for correctly. +# thoughts: use new element tag to indicate strBow(3). +# 1.5010r proposed enhancement. Adding character name to frames around stuff. +# - marking resolved... determined to not do. +# 1.5013o enhancement. this is for all "off-hand" attacks stuff. Eg: str bonus +# only 1/2 for "off-hand" for both to-hit and damage (unless penalty! ;-) +# Probably other things, as I see nothing in here to account for them. +# 1.5016o enhancement. swim check does not reflect weight check. +# 1.5018o enhancement. actual psionic abilities list. +# 1.6002o enhancement. modify code to take advanage of new footnote field for +# indicating which weapons are Thrown, as opposed to improvised thrown +# weapons; which are treated differently. Allow for throwing of melee +# weapons (with 1.6001 all melee are unthrowable) recast of 1.5011, +# which I'm marking resolved. +# 1.6004o feature request from 541659 Ability to remove skills, at least those +# that can't be used untrained. This would also require ability to re-add +# skills later. Short term solution may be to ability to clearly mark +# skill which can't be used yet. - low priority. +# 1.6005o feature request from 541659 Custom feats, without the need to edit +# data/dnd3e/dnd3efeats.xml Note, while standard feats may be affecting +# how tool will generate rolls, etc; it is unlikely that custom feats will +# will be able to do this; but should be able to be include from a +# complete "character sheet" perspective. - low priority (since +# dnd3efeats can be edited to add feats) +# 1.6006o feature request from 541659 Do sorcerer and bard spells right; +# for short term at least remove requirement to have to update +# memorized list. - med priority +# 1.6007o feature request from 541659 Make tabs optional to be able to remove +# tabs which are unused by a particular character. Would need ability +# to add them back in, since character might later add a class which +# would need them. - very low priority +# 1.6017o enhancement when editing footnotes for weapons, +# provide full table of footnotes in companion window to help. +# 1.6019o enhancement Forum request to add "flatfooted" to ac matrix +# 1.6020o enh add column to skills to allow tracking of skill points allocated. +# 1.9000r clean up of excess comments from 1.6 and earlier. +# 1.9001r if str or dex changes, Melee/Ranged combat ability does not update +# until refreshed by a change. +# 1.9002r depending on what subwindows were open, changing stat scores could +# crash out entire orpg environment. +# +# r- resolved +# o- open +# +import orpg.tools.orpg_settings +import orpg.minidom +from core import * +from containers import * +from string import * #a 1.6003 +from inspect import * #a 1.9001 +dnd3e_EXPORT = wx.NewId() +############Global Stuff############## + +HP_CUR = wx.NewId() +HP_MAX = wx.NewId() +PP_CUR = wx.NewId() +PP_MAX = wx.NewId() +PP_FRE = wx.NewId() +PP_MFRE = wx.NewId() +HOWTO_MAX = wx.NewId() + +def getRoot (node): # a 1.5002 this whole function is new. + root = None + target = node + while target != None: + root = target + target = target.hparent + return root +#o 1.5002 (this whole comment block) +# if a method runs getRoot for its instance and assigns the +# value returned to self.root, you can get to instances X via Y +# instance handle via invocation +# --------------- --- ----------- +# classes via self.root.classes +# abilities via self.root.abilities +# pp via self.root.pp +# general via self.root.general +# saves via self.root.saves +# attacks via self.root.attacks +# ac via self.root.ac +# feats via self.root.feats +# spells via self.root.spells +# divine via self.root.divine +# powers via self.root.powers +# inventory via self.root.inventory +# hp via self.root.hp +# skills via self.root.skills +#... if other instances are needed and the instance exists uniquely, +# add to the instance you need access to in the __init__ section the following: +# self.hparent = parent # or handler if a wx instance, also add up chain +# self.root = getRoot(self) +# self.root.{instance handle} = self +# # replace {instance handle} with your designation +# then, where you need access to the instance, simply add this to the instance +# that needs to reference +# self.hparent = getRoot(self) # in the init section, if not already there +# self.root = getRoot(self) # also in the init +# then to refer to the instance where you need it: +# self.root.{instance handle}.{whatever you need} +# # replace {instance handle} with your designation +# # replace {whatever you need} with the attribute/method u want. + +#d 1.6000 not used. +#def getCharacterProp(forgetIt): +# return None + +#a 1.6 convinience function added safeGetAttr +def safeGetAttr(node,lable,defRetV=None): + cna=node.attributes + for i2 in range(len(cna)): + if cna.item(i2).name == lable: + return cna.item(i2).value + #retV=node.getAttribute(lable) # getAttribute does not distingish between + # the attribute not being present vs it having a value of "" + # This is bad for this routine, thus not used. + return defRetV +#a 1.6... safeGetAttr end. + +########End of My global Stuff######## +########Start of Main Node Handlers####### +class dnd3echar_handler(container_handler): + """ Node handler for a dnd3e charactor + <nodehandler name='?' module='dnd3e' class='dnd3echar_handler2' /> + """ + def __init__(self,xml_dom,tree_node): + node_handler.__init__(self,xml_dom,tree_node) + self.Version = "v1.901" #a 1.6000 general documentation, usage. + + print "dnd3echar_handler - version:",self.Version #m 1.6000 + + self.hparent = None #a 1.5002 allow ability to run up tree, this is the + #a 1.5002 top of the handler tree, this is used to flag where to stop + #a 1.5002 on the way up. Changing this will break getRoot(self) + + self.frame = open_rpg.get_component('frame') + self.child_handlers = {} + self.new_child_handler('howtouse','HowTo use this tool',dnd3ehowto,'note') + self.new_child_handler('general','GeneralInformation',dnd3egeneral,'gear') + self.new_child_handler('inventory','MoneyAndInventory',dnd3einventory,'money') + self.new_child_handler('character','ClassesAndStats',dnd3eclassnstats,'knight') + self.new_child_handler('snf','SkillsAndFeats',dnd3eskillsnfeats,'book') + self.new_child_handler('combat','Combat',dnd3ecombat,'spears') + self.new_child_handler('snp','SpellsAndPowers',dnd3esnp,'flask') + #wxMenuItem(self.tree.std_menu, dnd3e_EXPORT, "Export...", "Export") + #print "dnd3echar_handler init - "+\ + # "self.child_handlers:",self.child_handlers # a (debug) 1.5002 + self.myeditor = None + + + def new_child_handler(self,tag,text,handler_class,icon='gear'): + node_list = self.master_dom.getElementsByTagName(tag) + tree = self.tree + i = self.tree.icons[icon] + new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) + handler = handler_class(node_list[0],new_tree_node,self) + tree.SetPyData(new_tree_node,handler) + self.child_handlers[tag] = handler + + def get_design_panel(self,parent): + return tabbed_panel(parent,self,1) + + + def get_use_panel(self,parent): + return tabbed_panel(parent,self,2) + + def tohtml(self): + html_str = "<table><tr><td colspan=2 >" + #d block for 1.6009 start + #html_str += self.child_handlers['general'].tohtml()+"</td></tr>" + #html_str += "<tr><td width='50%' valign=top > + # "+self.child_handlers['abilities'].tohtml() + #html_str += "<P>" + self.child_handlers['saves'].tohtml() + #html_str += "<P>" + self.child_handlers['attacks'].tohtml() + #html_str += "<P>" + self.child_handlers['ac'].tohtml() + #html_str += "<P>" + self.child_handlers['feats'].tohtml() + #html_str += "<P>" + self.child_handlers['spells'].tohtml() + #html_str += "<P>" + self.child_handlers['divine'].tohtml() + #html_str += "<P>" + self.child_handlers['powers'].tohtml() + #html_str += "<P>" + self.child_handlers['inventory'].tohtml() +"</td>" + #html_str += "<td width='50%' valign=top > + # "+self.child_handlers['classes'].tohtml() + #html_str += "<P>" + self.child_handlers['hp'].tohtml() + #html_str += "<P>" + self.child_handlers['pp'].tohtml() + #html_str += "<P>" + self.child_handlers['skills'].tohtml() +"</td>" + #d block for 1.6009 end + #a block for 1.6009 start + html_str += self.general.tohtml()+"</td></tr>" + html_str += "<tr><td width='50%' valign=top >"+self.abilities.tohtml() + html_str += "<P>" + self.saves.tohtml() + html_str += "<P>" + self.attacks.tohtml() + html_str += "<P>" + self.ac.tohtml() + html_str += "<P>" + self.feats.tohtml() + html_str += "<P>" + self.spells.tohtml() + html_str += "<P>" + self.divine.tohtml() + html_str += "<P>" + self.powers.tohtml() + html_str += "<P>" + self.inventory.tohtml() +"</td>" + html_str += "<td width='50%' valign=top >"+self.classes.tohtml() + html_str += "<P>" + self.hp.tohtml() + html_str += "<P>" + self.pp.tohtml() + html_str += "<P>" + self.skills.tohtml() +"</td>" + #a block for 1.6009 end + + html_str += "</tr></table>" + return html_str + + def about(self): + html_str = "<img src='" + orpg.dirpath.dir_struct["icon"] + html_str += "dnd3e_logo.gif' ><br><b>dnd3e Character Tool " + html_str += self.Version+"</b>" #m 1.6000 was hard coded. + html_str += "<br>by Dj Gilcrease<br>digitalxero@gmail.com" + return html_str + +########Core Handlers are done now############ +########Onto the Sub Nodes######## +##Primary Sub Node## + +class outline_panel(wx.Panel): + def __init__(self, parent, handler, wnd, txt,): + self.parent = parent #a 1.9001 + wx.Panel.__init__(self, parent, -1) + self.panel = wnd(self,handler) + self.sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,txt), wx.VERTICAL) + + self.sizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + +class dnd3e_char_child(node_handler): + """ Node Handler for skill. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.char_hander = parent + self.drag = False + self.frame = open_rpg.get_component('frame') + self.myeditor = None + + + def on_drop(self,evt): + pass + + def on_rclick(self,evt): + pass + + def on_ldclick(self,evt): + return + + def on_html(self,evt): + html_str = self.tohtml() + wnd = http_html_window(self.frame.note,-1) + wnd.title = self.master_dom.getAttribute('name') + self.frame.add_panel(wnd) + wnd.SetPage(html_str) + + def get_design_panel(self,parent): + pass + + def get_use_panel(self,parent): + return self.get_design_panel(parent) + + def delete(self): + pass + +###Child Nodes Organized the way they are in the XML for easier viewing#### #m 1.5002 corrected typo. +class dnd3ehowto(dnd3e_char_child): #m 1.5002 corrected string below to reflect "how to" + """ Node Handler for how to instructions. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + + def get_design_panel(self,parent): + wnd = howto_panel(parent, self) + wnd.title = "How To" + return wnd + +class howto_panel(wx.Panel): + def __init__(self, parent, handler): + wx.Panel.__init__(self, parent, -1) + + pname = handler.master_dom.setAttribute("name", 'How To') + self.sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, 'How To'), wx.VERTICAL) + self.master_dom = handler.master_dom + n_list = self.master_dom._get_childNodes() + for n in n_list: + t_node = safe_get_text_node(n) + self.sizer.Add(wx.StaticText(self, -1, t_node._get_nodeValue()), 1, wx.EXPAND) + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + +class dnd3egeneral(dnd3e_char_child): + """ Node Handler for general information. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.general = self #a 1.5002 + self.charName = self.get_char_name() # a 1.5002 make getting name easier. + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,gen_grid,"General Information") + wnd.title = "General Info" + return wnd + + def tohtml(self): + n_list = self.master_dom._get_childNodes() + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>" + for n in n_list: + t_node = safe_get_text_node(n) + html_str += "<B>"+n._get_tagName().capitalize() +":</B> " + html_str += t_node._get_nodeValue() + ", " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + + def on_name_change(self,name): + self.char_hander.rename(name) + #o 1.5002 self.char_hander = parent in this case. + self.charName = name #a 1.5002 make getting name easier. + + + def get_char_name( self ): + node = self.master_dom.getElementsByTagName( 'name' )[0] + t_node = safe_get_text_node( node ) + return t_node._get_nodeValue() + +class gen_grid(wx.grid.Grid): + """grid for gen info""" + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'General') + self.hparent = handler #a 1.5002 allow ability to run up tree, needed + # a 1.5002 parent is functional parent, not invoking parent. + + + wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.handler = handler + n_list = handler.master_dom._get_childNodes() + self.CreateGrid(len(n_list),2) + self.SetRowLabelSize(0) + self.SetColLabelSize(0) + self.n_list = n_list + i = 0 + for i in range(len(n_list)): + self.refresh_row(i) + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.GetCellValue(row,col) + t_node = self.n_list[row]._get_firstChild() + t_node._set_nodeValue(value) + if row==0: + self.handler.on_name_change(value) + self.AutoSizeColumn(1) + + def refresh_row(self,rowi): + t_node = safe_get_text_node(self.n_list[rowi]) + + self.SetCellValue(rowi,0,self.n_list[rowi]._get_tagName()) + self.SetReadOnly(rowi,0) + self.SetCellValue(rowi,1,t_node._get_nodeValue()) + self.AutoSizeColumn(1) + +class dnd3einventory(dnd3e_char_child): + """ Node Handler for general information. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.6009 + self.root.inventory = self #a 1.6009 + + def get_design_panel(self,parent): + wnd = inventory_pane(parent, self) #outline_panel(parent,self,inventory_grid,"Inventory") + wnd.title = "General Info" + return wnd + + def tohtml(self): + n_list = self.master_dom._get_childNodes() + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>" + for n in n_list: + t_node = safe_get_text_node(n) + html_str += "<B>"+n._get_tagName().capitalize() +":</B> " + html_str += t_node._get_nodeValue() + "<br>" + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + +class inventory_pane(wx.Panel): + def __init__(self, parent, handler): + wx.Panel.__init__(self, parent, wx.ID_ANY) + + self.n_list = handler.master_dom._get_childNodes() + self.autosize = False + + self.sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Inventroy"), wx.VERTICAL) + + self.lang = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Languages") + self.gear = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Gear") + self.magic = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Magic") + self.grid = wx.grid.Grid(self, wx.ID_ANY, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + + self.grid.CreateGrid(len(self.n_list)-3,2) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelSize(0) + + for i in xrange(len(self.n_list)): + self.refresh_row(i) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(self.grid, 1, wx.EXPAND) + sizer1.Add(self.lang, 1, wx.EXPAND) + + self.sizer.Add(sizer1, 0, wx.EXPAND) + + sizer2 = wx.BoxSizer(wx.HORIZONTAL) + sizer2.Add(self.gear, 1, wx.EXPAND) + sizer2.Add(self.magic, 1, wx.EXPAND) + + self.sizer.Add(sizer2, 1, wx.EXPAND) + + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.lang) + self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.gear) + self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.magic) + self.Bind(wx.grid.EVT_GRID_EDITOR_HIDDEN, self.on_cell_change, self.grid) + + + def fillTextNode(self, name, value): + if name == 'Languages': + self.lang.SetValue(value) + elif name == 'Gear': + self.gear.SetValue(value) + elif name == 'Magic': + self.magic.SetValue(value) + + def onTextNodeChange(self, event): + id = event.GetId() + + if id == self.gear.GetId(): + nodeName = 'Gear' + value = self.gear.GetValue() + elif id == self.magic.GetId(): + nodeName = 'Magic' + value = self.magic.GetValue() + elif id == self.lang.GetId(): + nodeName = 'Languages' + value = self.lang.GetValue() + + for node in self.n_list: + if node._get_tagName() == nodeName: + t_node = safe_get_text_node(node) + t_node._set_nodeValue(value) + + def saveMoney(self, row, col): + value = self.grid.GetCellValue(row, col) + t_node = safe_get_text_node(self.n_list[row]) + t_node._set_nodeValue(value) + + def on_cell_change(self, evt): + row = evt.GetRow() + col = evt.GetCol() + self.grid.AutoSizeColumn(col) + wx.CallAfter(self.saveMoney, row, col) + + + + def refresh_row(self, row): + t_node = safe_get_text_node(self.n_list[row]) + tagname = self.n_list[row]._get_tagName() + value = t_node._get_nodeValue() + if tagname == 'Gear': + self.fillTextNode(tagname, value) + elif tagname == 'Magic': + self.fillTextNode(tagname, value) + elif tagname == 'Languages': + self.fillTextNode(tagname, value) + else: + self.grid.SetCellValue(row, 0, tagname) + self.grid.SetReadOnly(row, 0) + self.grid.SetCellValue(row, 1, value) + self.grid.AutoSize() + + +class dnd3eclassnstats(dnd3e_char_child): + """ Node handler for a dnd3e charactor + <nodehandler name='?' module='dnd3e' class='dnd3echar_handler2' /> + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.hparent = parent #a 1.5002 allow ability to run up tree. + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.frame = open_rpg.get_component('frame') + self.child_handlers = {} + self.new_child_handler('abilities','Abilities Scores',dnd3eability,'gear') + self.new_child_handler('classes','Classes',dnd3eclasses,'knight') + self.new_child_handler('saves','Saves',dnd3esaves,'skull') + self.myeditor = None + + + def new_child_handler(self,tag,text,handler_class,icon='gear'): + node_list = self.master_dom.getElementsByTagName(tag) + tree = self.tree + i = self.tree.icons[icon] + new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) + handler = handler_class(node_list[0],new_tree_node,self) + tree.SetPyData(new_tree_node,handler) + self.child_handlers[tag] = handler + + def get_design_panel(self,parent): + return tabbed_panel(parent,self,1) + + + def get_use_panel(self,parent): + return tabbed_panel(parent,self,2) + +class class_char_child(node_handler): + """ Node Handler for skill. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.char_hander = parent + self.drag = False + self.frame = open_rpg.get_component('frame') + self.myeditor = None + + def on_drop(self,evt): + pass + + def on_rclick(self,evt): + pass + + def on_ldclick(self,evt): + return + + def on_html(self,evt): + html_str = self.tohtml() + wnd = http_html_window(self.frame.note,-1) + wnd.title = self.master_dom.getAttribute('name') + self.frame.add_panel(wnd) + wnd.SetPage(html_str) + + def get_design_panel(self,parent): + pass + + def get_use_panel(self,parent): + return self.get_design_panel(parent) + + def delete(self): + pass + +class dnd3eability(class_char_child): + """ Node Handler for ability. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + class_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 get top of our local function tree. + self.root.abilities = self #a 1.5002 let other classes find me. + + self.abilities = {} + node_list = self.master_dom.getElementsByTagName('stat') + tree = self.tree + icons = tree.icons + + for n in node_list: + name = n.getAttribute('abbr') + self.abilities[name] = n + new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] ) + tree.SetPyData( new_tree_node, self ) + #print "dnd3eability - init self.abilities",self.abilities #a (debug) 1.5002 + + def on_rclick( self, evt ): + item = self.tree.GetSelection() + name = self.tree.GetItemText( item ) + #if item == self.mytree_node: #d 1.6016 + # dnd3e_char_child.on_ldclick( self, evt ) #d 1.6016 + if not item == self.mytree_node: #a 1.6016 + #else: #d 1.6016 + mod = self.get_mod( name ) + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + chat = self.chat + txt = '%s check: [1d20%s%s]' % ( name, mod1, mod ) + chat.ParsePost( txt, True, True ) + + def get_mod(self,abbr): + score = int(self.abilities[abbr].getAttribute('base')) + mod = (score - 10) / 2 + mod = int(mod) + return mod + + def set_score(self,abbr,score): + if score >= 0: + self.abilities[abbr].setAttribute("base",str(score)) + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,abil_grid,"Abilities") + wnd.title = "Abilities (edit)" + return wnd + + def tohtml(self): + html_str = """<table border='1' width=100%><tr BGCOLOR=#E9E9E9 ><th width='50%'>Ability</th> + <th>Base</th><th>Modifier</th></tr>""" + node_list = self.master_dom.getElementsByTagName('stat') + for n in node_list: + name = n.getAttribute('name') + abbr = n.getAttribute('abbr') + base = n.getAttribute('base') + mod = str(self.get_mod(abbr)) + if int(mod) >= 0: #m 1.6013 added "int(" and ")" + mod1 = "+" + else: + mod1 = "" + html_str = (html_str + "<tr ALIGN='center'><td>"+ + name+"</td><td>"+base+'</td><td>%s%s</td></tr>' % (mod1, mod)) + html_str = html_str + "</table>" + return html_str + +class abil_grid(wx.grid.Grid): + """grid for abilities""" + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Stats') + self.hparent = handler #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + + wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.handler = handler + stats = handler.master_dom.getElementsByTagName('stat') + self.CreateGrid(len(stats),3) + self.SetRowLabelSize(0) + col_names = ['Ability','Score','Modifier'] + for i in range(len(col_names)): + self.SetColLabelValue(i,col_names[i]) + self.stats = stats + i = 0 + for i in range(len(stats)): + self.refresh_row(i) + self.char_wnd = None + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.GetCellValue(row,col) + #print value + try: + int(value) + self.stats[row].setAttribute('base',value) + self.refresh_row(row) + except: + self.SetCellValue(row,col,"0") + if self.char_wnd: + self.char_wnd.refresh_data() + + #mark5 + + def refresh_row(self,rowi): + s = self.stats[rowi] + + name = s.getAttribute('name') + abbr = s.getAttribute('abbr') + self.SetCellValue(rowi,0,name) + self.SetReadOnly(rowi,0) + self.SetCellValue(rowi,1,s.getAttribute('base')) + self.SetCellValue(rowi,2,str(self.handler.get_mod(abbr))) + self.SetReadOnly(rowi,2) + #if self.root.saves.saveGrid: #a 1.6018 d 1.9002 whole if clause + #print getmembers(self.root.saves.saveGrid) + #self.root.saves.saveGrid.refresh_data() #a 1.6018 + #print "skipping saving throw update, put back in later" + self.root.saves.refresh_data() #a 1.9002 + self.root.attacks.refreshMRdata() #a 1.9001 ` + + def on_size(self,evt): + (w,h) = self.GetClientSizeTuple() + cols = self.GetNumberCols() + col_w = w/(cols+2) + self.SetColSize(0,col_w*3) + for i in range(1,cols): + self.SetColSize(i,col_w) + evt.Skip() + self.Refresh() + + def refresh_data(self): + for r in range(self.GetNumberRows()-1): + self.refresh_row(r) + +class dnd3eclasses(class_char_child): + """ Node Handler for classes. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + class_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) + self.root.classes = self + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,class_panel,"Classes") + wnd.title = "Classes" + return wnd + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Classes</th></tr><tr><td>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += n.getAttribute('name') + " ("+n.getAttribute('level')+"), " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + + def get_char_lvl( self, attr ): + node_list = self.master_dom.getElementsByTagName('class') + # print "eclasses - get_char_lvl node_list",node_list + tot = 0 #a 1.5009 actually, slipping in a quick enhancement ;-) + for n in node_list: + lvl = n.getAttribute('level') #o 1.5009 not sure of the value of this + tot += int(lvl) #a 1.5009 + type = n.getAttribute('name') #o 1.5009 not sure of the value of this + #print type,lvl #a (debug) 1.5009 + if attr == "level": + return lvl #o 1.5009 this returns the level of someone's first class. ??? + elif attr == "class": + return type #o 1.5009 this returns one of the char's classes. ??? + if attr == "lvl": #a 1.5009 this has value, adding this. + return tot #a 1.5009 return character's "overall" level. + + def get_class_lvl( self, classN ): #a 1.5009 need to be able to get monk lvl + #a 1.5009 this function is new. + node_list = self.master_dom.getElementsByTagName('class') + #print "eclasses - get_class_lvl node_list",node_list + for n in node_list: + lvl = n.getAttribute('level') + type = n.getAttribute('name') + if classN == type: + return lvl + +class class_panel(wx.Panel): + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Class') + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Class"), 0, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Class"), 0, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) + self.Bind(wx.EVT_BUTTON, self.on_add, id=20) + self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + self.master_dom = handler.master_dom + self.grid.CreateGrid(len(n_list),2,1) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelValue(0,"Class") + self.grid.SetColLabelValue(1,"Level") + for i in range(len(n_list)): + self.refresh_row(i) + self.temp_dom = None + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + try: + int(value) + self.n_list[row].setAttribute('level',value) + except: + self.grid.SetCellValue(row,col,"1") + + + def refresh_row(self,i): + n = self.n_list[i] + + name = n.getAttribute('name') + level = n.getAttribute('level') + self.grid.SetCellValue(i,0,name) + self.grid.SetReadOnly(i,0) + self.grid.SetCellValue(i,1,level) + #self.grid.SetReadOnly(i,1) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3eclasses.xml","r") + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('class') + opts = [] + for f in f_list: + opts.append(f.getAttribute('name')) + dlg = wx.SingleChoiceDialog(self,'Choose Class','Classes',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.refresh_row(self.grid.GetNumberRows()-1) + dlg.Destroy() + + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols) + for i in range(0,cols): + self.grid.SetColSize(i,col_w) + + +class dnd3esaves(class_char_child): + """ Node Handler for saves. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + class_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + #self.saveGrid = None #a 1.6018 d 1.9002 + self.saveGridFrame = [] #a 1.9002 handle list, check frame for close. + + tree = self.tree + icons = self.tree.icons + + self.root = getRoot(self) #a 1.5002 + self.root.saves = self #a 1.6009 + node_list = self.master_dom.getElementsByTagName('save') + self.saves={} + for n in node_list: + name = n.getAttribute('name') + self.saves[name] = n + new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear']) + tree.SetPyData(new_tree_node,self) + + #a 1.9002 this whole method + def refresh_data(self): # refresh the data in the melee/ranged section + # of the attack chart. + # count backwards, maintains context despite "removes" + for i in range(len(self.saveGridFrame)-1,-1,-1): + x = self.saveGridFrame[i] + if x == None: + x.refresh_data() + else: + self.saveGridFrame.remove(x) + + def get_mod(self,name): + save = self.saves[name] + stat = save.getAttribute('stat') + #print "dnd3esaves, get_mod: self,root",self,self.root #a (debug) 1.5002 + #print "and abilities",self.root.abilities #a (debug) 1.5002 + stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 + base = int(save.getAttribute('base')) + miscmod = int(save.getAttribute('miscmod')) + magmod = int(save.getAttribute('magmod')) + total = stat_mod + base + miscmod + magmod + return total + + def on_rclick(self,evt): + + item = self.tree.GetSelection() + name = self.tree.GetItemText(item) + if item == self.mytree_node: + pass #a 1.5003 syntatic place holder + return #a 1.5003 + #print "failure mode!" + #dnd3e_char_child.on_ldclick(self,evt) #d 1.5003 this busted + #wnd = save_grid(self.frame.note,self) + #wnd.title = "Saves" + #self.frame.add_panel(wnd) + else: + mod = self.get_mod(name) + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + chat = self.chat + txt = '%s save: [1d20%s%s]' % (name, mod1, mod) + chat.ParsePost( txt, True, True ) + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,save_grid,"Saves") + wnd.title = "Saves" + return wnd + + def tohtml(self): + html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > + <th width='30%'>Save</th> + <th>Key</th><th>Base</th><th>Abil</th><th>Magic</th> + <th>Misc</th><th>Total</th></tr>""" + node_list = self.master_dom.getElementsByTagName('save') + for n in node_list: + name = n.getAttribute('name') + stat = n.getAttribute('stat') + base = n.getAttribute('base') + html_str = html_str + "<tr ALIGN='center'><td>"+name+"</td><td>"+stat+"</td><td>"+base+"</td>" + #stat_mod = str(dnd_globals["stats"][stat]) #d 1.5002 + stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 + + mag = n.getAttribute('magmod') + misc = n.getAttribute('miscmod') + mod = str(self.get_mod(name)) + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + #m 1.5009 next line. added str() around stat_mod + html_str = html_str + "<td>"+str(stat_mod)+"</td><td>"+mag+"</td>" + html_str = html_str + '<td>'+misc+'</td><td>%s%s</td></tr>' % (mod1, mod) + html_str = html_str + "</table>" + return html_str + +#mark6 +class save_grid(wx.grid.Grid): + """grid for saves""" + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Saves') + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + self.root = getRoot(self) + + #self.hparent.saveGrid = self #a 1.6018 d 1.9001 + + + wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.handler = handler + saves = handler.master_dom.getElementsByTagName('save') + self.CreateGrid(len(saves),7) + self.SetRowLabelSize(0) + col_names = ['Save','Key','base','Abil','Magic','Misc','Total'] + for i in range(len(col_names)): + self.SetColLabelValue(i,col_names[i]) + self.saves = saves + i = 0 + for i in range(len(saves)): + self.refresh_row(i) + + + #a 1.9002 remainder of code in this method. + climber = parent + nameNode = climber.GetClassName() + while nameNode != 'wxFrame': + climber = climber.parent + nameNode = climber.GetClassName() + masterFrame=climber + masterFrame.refresh_data=self.refresh_data + #print getmembers(masterFrame) + + handler.saveGridFrame.append(masterFrame) + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.GetCellValue(row,col) + try: + int(value) + if col == 2: + self.saves[row].setAttribute('base',value) + elif col ==4: + self.saves[row].setAttribute('magmod',value) + elif col ==5: # 1.5001 + self.saves[row].setAttribute('miscmod',value) + self.refresh_row(row) + except: + self.SetCellValue(row,col,"0") + + def refresh_row(self,rowi): + s = self.saves[rowi] + + name = s.getAttribute('name') + self.SetCellValue(rowi,0,name) + self.SetReadOnly(rowi,0) + stat = s.getAttribute('stat') + self.SetCellValue(rowi,1,stat) + self.SetReadOnly(rowi,1) + self.SetCellValue(rowi,2,s.getAttribute('base')) + self.SetCellValue(rowi,3,str(self.root.abilities.get_mod(stat))) + self.SetReadOnly(rowi,3) + self.SetCellValue(rowi,4,s.getAttribute('magmod')) + self.SetCellValue(rowi,5,s.getAttribute('miscmod')) + mod = str(self.handler.get_mod(name)) + self.SetCellValue(rowi,6,mod) + self.SetReadOnly(rowi,6) + + def on_size(self,evt): + (w,h) = self.GetClientSizeTuple() + cols = self.GetNumberCols() + col_w = w/(cols+2) + self.SetColSize(0,col_w*3) + for i in range(1,cols): + self.SetColSize(i,col_w) + evt.Skip() + self.Refresh() + + def refresh_data(self): + for r in range(self.GetNumberRows()): + self.refresh_row(r) + +class dnd3eskillsnfeats(dnd3e_char_child): + """ Node handler for a dnd3e charactor + <nodehandler name='?' module='dnd3e' class='dnd3echar_handler2' /> + """ + def __init__(self,xml_dom,tree_node,parent): + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.6009 + + #print "dnd3eskillsnfeats - init, self ",self #a (debug) 1.5002 + #print "dnd3eskillsnfeats - init, parent ",self.hparent #a (debug) 1.5002 + #print "dnd3eskillsnfeats - init, parent ",parent.dnd3eclassnstats #a (debug) 1.5002 + + node_handler.__init__(self,xml_dom,tree_node) + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.frame = open_rpg.get_component('frame') + self.child_handlers = {} + self.new_child_handler('skills','Skills',dnd3eskill,'book') + self.new_child_handler('feats','Feats',dnd3efeats,'book') + #wxMenuItem(self.tree.std_menu, dnd3e_EXPORT, "Export...", "Export") + self.myeditor = None + + + def new_child_handler(self,tag,text,handler_class,icon='gear'): + node_list = self.master_dom.getElementsByTagName(tag) + tree = self.tree + i = self.tree.icons[icon] + new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) + handler = handler_class(node_list[0],new_tree_node,self) + tree.SetPyData(new_tree_node,handler) + self.child_handlers[tag] = handler + + def get_design_panel(self,parent): + return tabbed_panel(parent,self,1) + + + def get_use_panel(self,parent): + return tabbed_panel(parent,self,2) + +class skills_char_child(node_handler): + """ Node Handler for skill. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.char_hander = parent + self.drag = False + self.frame = open_rpg.get_component('frame') + self.myeditor = None + + + + def on_drop(self,evt): + pass + + def on_rclick(self,evt): + pass + + def on_ldclick(self,evt): + return + + def on_html(self,evt): + html_str = self.tohtml() + wnd = http_html_window(self.frame.note,-1) + wnd.title = self.master_dom.getAttribute('name') + self.frame.add_panel(wnd) + wnd.SetPage(html_str) + + def get_design_panel(self,parent): + pass + + def get_use_panel(self,parent): + return self.get_design_panel(parent) + + def delete(self): + pass + +class dnd3eskill(skills_char_child): + """ Node Handler for skill. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + self.hparent = parent #a 1.5002 allow ability to run up tree. + #a 1.5002 Need the functional parent, not the invoking parent. + self.root = getRoot(self) #a 1.5002 + self.root.skills = self #a 1.6009 + + skills_char_child.__init__(self,xml_dom,tree_node,parent) + tree = self.tree + icons = self.tree.icons + node_list = self.master_dom.getElementsByTagName('skill') + + self.skills={} + #Adding code to not display skills you can not use -mgt + for n in node_list: + name = n.getAttribute('name') + self.skills[name] = n + skill_check = self.skills[name] + ranks = int(skill_check.getAttribute('rank')) + trained = int(skill_check.getAttribute('untrained')) + + if ranks > 0 or trained == 1: + new_tree_node = tree.AppendItem(self.mytree_node,name, + icons['gear'],icons['gear']) + else: + continue + + tree.SetPyData(new_tree_node,self) + + + + def refresh_skills(self): + #Adding this so when you update the grid the tree will reflect + #The change. -mgt + tree = self.tree + icons = self.tree.icons + tree.CollapseAndReset(self.mytree_node) + node_list = self.master_dom.getElementsByTagName('skill') + + self.skills={} + for n in node_list: + name = n.getAttribute('name') + self.skills[name] = n + skill_check = self.skills[name] + ranks = int(skill_check.getAttribute('rank')) + trained = int(skill_check.getAttribute('untrained')) + + if ranks > 0 or trained == 1: + new_tree_node = tree.AppendItem(self.mytree_node,name, + icons['gear'],icons['gear']) + else: + continue + + tree.SetPyData(new_tree_node,self) + + def get_mod(self,name): + skill = self.skills[name] + stat = skill.getAttribute('stat') + #stat_mod = int(dnd_globals["stats"][stat]) #d 1.5002 + stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 + rank = int(skill.getAttribute('rank')) + misc = int(skill.getAttribute('misc')) + total = stat_mod + rank + misc + return total + + def on_rclick(self,evt): + item = self.tree.GetSelection() + name = self.tree.GetItemText(item) + #print "skill rc self",self #a 1.6004 + #print "skill rc tree",self.mytree_node #a 1.6004 + #print "skill rc item",item #a 1.6004 + if item == self.mytree_node: + return + # following line fails, + #dnd3e_char_child.on_ldclick(self,evt) #d 1.6014 + # it's what it used to try to do. + ac = self.root.ac.get_check_pen() #a 1.5002 for 1.5004 verify fix. + + skill = self.skills[name] + + untr = skill.getAttribute('untrained') #a 1.6004 + rank = skill.getAttribute('rank') #a 1.6004 + if eval('%s == 0' % (untr)): #a 1.6004 + if eval('%s == 0' % (rank)): #a 1.6004 + res = 'You fumble around, accomplishing nothing' #a 1.6004 + txt = '%s Skill Check: %s' % (name, res) #a 1.6004 + chat = self.chat #a 1.6004 + chat.Post(txt,True,True) #a 1.6004 + return #a 1.6004 + + armor = '' + acCp = '' + if ac < 0: #acCp >= 1 #m 1.5004 this is stored as negatives. + armorCheck = int(skill.getAttribute('armorcheck')) + #print "ac,armorCheck",ac,armorCheck + if armorCheck == 1: + acCp=ac + armor = '(includes Armor Penalty of %s)' % (acCp) + if item == self.mytree_node: + dnd3e_char_child.on_ldclick(self,evt) + #wnd = skill_grid(self.frame.note,self) + #wnd.title = "Skills" + #self.frame.add_panel(wnd) + else: + mod = self.get_mod(name) + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + chat = self.chat + txt = '%s Skill Check: [1d20%s%s%s] %s' % ( + name, mod1, mod, acCp, armor) + chat.ParsePost(txt,True,True) + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,skill_grid,"Skills") + wnd.title = "Skills (edit)" + return wnd + + def tohtml(self): + html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > + <th width='30%'>Skill</th><th>Key</th> + <th>Rank</th><th>Abil</th><th>Misc</th><th>Total</th></tr>""" + node_list = self.master_dom.getElementsByTagName('skill') + + for n in node_list: + name = n.getAttribute('name') + stat = n.getAttribute('stat') + rank = n.getAttribute('rank') + untr = n.getAttribute('untrained') #a 1.6004 + #Filter unsuable skills out of pretty print -mgt + if eval('%s > 0' % (rank)) or eval('%s == 1' % (untr)): + if eval('%s >=1' % (rank)): + html_str += "<tr ALIGN='center' bgcolor='#CCCCFF'><td>" #a 1.6004 + #html_str += "<tr ALIGN='center' bgcolor='green'><td>" #d 1.6004 + html_str += name+"</td><td>"+stat+"</td><td>"+rank+"</td>" + elif eval('%s == 1' % (untr)): #a 1.6004 + html_str += "<tr ALIGN='center' bgcolor='#C0FF40'><td>" #a 1.6004 + html_str += name+"</td><td>"+stat+"</td><td>"+rank+"</td>" #a 1.6004 + else: + html_str += "<tr ALIGN='center'><td>"+name+"</td><td>" + html_str += stat+"</td><td>"+rank+"</td>" + else: + continue + stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 + #stat_mod = str(dnd_globals["stats"][stat]) #d 1.5002 + misc = n.getAttribute('misc') + mod = str(self.get_mod(name)) + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + html_str += "<td>"+str(stat_mod)+"</td><td>"+misc #m 1.6009 str() + html_str += '</td><td>%s%s</td></tr>' % (mod1, mod) + html_str = html_str + "</table>" + return html_str + + +class skill_grid(wx.grid.Grid): + """ panel for skills """ + def __init__(self, parent, handler): + self.hparent = handler #a 1.5002 need function parent, not invoker + self.root = getRoot(self) #a 1.5002 + pname = handler.master_dom.setAttribute("name", 'Skills') + + wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.handler = handler + skills = handler.master_dom.getElementsByTagName('skill') + #xelf.stats = dnd_globals["stats"] #d 1.5002 + + self.CreateGrid(len(skills),6) + self.SetRowLabelSize(0) + col_names = ['Skill','Key','Rank','Abil','Misc','Total'] + for i in range(len(col_names)): + self.SetColLabelValue(i,col_names[i]) + rowi = 0 + self.skills = skills + for i in range(len(skills)): + self.refresh_row(i) + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.GetCellValue(row,col) + #print value + try: + int(value) + if col == 2: + self.skills[row].setAttribute('rank',value) + elif col ==4: + self.skills[row].setAttribute('misc',value) + self.refresh_row(row) + except: + self.SetCellValue(row,col,"0") + + #call refresh_skills + self.handler.refresh_skills() + + def refresh_row(self,rowi): + s = self.skills[rowi] + name = s.getAttribute('name') + self.SetCellValue(rowi,0,name) + self.SetReadOnly(rowi,0) + stat = s.getAttribute('stat') + self.SetCellValue(rowi,1,stat) + self.SetReadOnly(rowi,1) + self.SetCellValue(rowi,2,s.getAttribute('rank')) + #self.SetCellValue(rowi,3,str(dnd_globals["stats"][stat])) #d 1.5002 + if self.root.abilities: #a 1.5002 sanity check. + stat_mod=self.root.abilities.get_mod(stat) #a 1.5002 + else: #a 1.5002 + stat_mod = -6 #a 1.5002 this can happen if code is changed so + #a 1.5002 that abilities are not defined prior invokation of init. + print "Please advise dnd3e maintainer alert 1.5002 raised" + + self.SetCellValue(rowi,3,str(stat_mod)) #a 1.5002 + self.SetReadOnly(rowi,3) + self.SetCellValue(rowi,4,s.getAttribute('misc')) + mod = str(self.handler.get_mod(name)) + self.SetCellValue(rowi,5,mod) + self.SetReadOnly(rowi,5) + + def on_size(self,evt): + (w,h) = self.GetClientSizeTuple() + cols = self.GetNumberCols() + col_w = w/(cols+2) + self.SetColSize(0,col_w*3) + for i in range(1,cols): + self.SetColSize(i,col_w) + evt.Skip() + self.Refresh() + + def refresh_data(self): + + for r in range(self.GetNumberRows()): + self.refresh_row(r) + + + + +class dnd3efeats(skills_char_child): + """ Node Handler for classes. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + skills_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.feats = self #a 1.6009 + + + def get_design_panel(self,parent): + setTitle="Feats - " + self.root.general.charName #a 1.5010 + wnd = outline_panel(parent,self,feat_panel,setTitle) #a 1.5010 + #wnd = outline_panel(parent,self,feat_panel,"Feats") #d 1.5010 + wnd.title = "Feats" #d 1.5010 + #wnd.title = "Feats - " + self.charName + return wnd + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Feats</th></tr><tr><td>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += n.getAttribute('name')+ ", " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + +class feat_panel(wx.Panel): + def __init__(self, parent, handler): + + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + self.root = getRoot(self) #a 1.5002 + #tempTitle= 'Feats - ' + self.root.general.charName #a 1.5010 + #pname = handler.master_dom.setAttribute("name", tempTitle) #a 1.5010 + pname = handler.master_dom.setAttribute("name", 'Feats') #d 1.5010 + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Feat"), 0, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Feat"), 0, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + self.sizer = sizer + + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) + self.Bind(wx.EVT_BUTTON, self.on_add, id=20) + + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + self.master_dom = handler.master_dom + self.grid.CreateGrid(len(n_list),3,1) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelValue(0,"Feat") + self.grid.SetColLabelValue(1,"Type") + self.grid.SetColLabelValue(2,"Reference") #m 1.6 typo correction. + for i in range(len(n_list)): + self.refresh_row(i) + self.temp_dom = None + + def refresh_row(self,i): + feat = self.n_list[i] + + name = feat.getAttribute('name') + type = feat.getAttribute('type') + desc = feat.getAttribute('desc') #m 1.6 correct typo + self.grid.SetCellValue(i,0,name) + self.grid.SetReadOnly(i,0) + self.grid.SetCellValue(i,1,type) + self.grid.SetReadOnly(i,1) + self.grid.SetCellValue(i,2,desc) #m 1.6 correct typo + self.grid.SetReadOnly(i,2) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3efeats.xml","r") + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('feat') + opts = [] + for f in f_list: + opts.append(f.getAttribute('name') + " - [" + + f.getAttribute('type') + "] - " + f.getAttribute('desc')) + dlg = wx.SingleChoiceDialog(self,'Choose Feat','Feats',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.refresh_row(self.grid.GetNumberRows()-1) + dlg.Destroy() + + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols) + for i in range(0,cols): + self.grid.SetColSize(i,col_w) + +class dnd3ecombat(dnd3e_char_child): + """ Node handler for a dnd3e charactor + <nodehandler name='?' module='dnd3e' class='dnd3echar_handler2' /> + """ + def __init__(self,xml_dom,tree_node,parent): + + node_handler.__init__(self,xml_dom,tree_node) + + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5012 + + + + #mark3 + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.frame = open_rpg.get_component('frame') + self.child_handlers = {} + self.new_child_handler('hp','Hit Points',dnd3ehp,'gear') + self.new_child_handler('attacks','Attacks',dnd3eattacks,'spears') + self.new_child_handler('ac','Armor',dnd3earmor,'spears') + #print "combat",self.child_handlers #a (debug) 1.5002 + #wxMenuItem(self.tree.std_menu, dnd3e_EXPORT, "Export...", "Export") + self.myeditor = None + + + def new_child_handler(self,tag,text,handler_class,icon='gear'): + node_list = self.master_dom.getElementsByTagName(tag) + tree = self.tree + i = self.tree.icons[icon] + new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) + handler = handler_class(node_list[0],new_tree_node,self) + tree.SetPyData(new_tree_node,handler) + self.child_handlers[tag] = handler + + def get_design_panel(self,parent): + return tabbed_panel(parent,self,1) + + def get_use_panel(self,parent): + return tabbed_panel(parent,self,2) + + +class combat_char_child(node_handler): + """ Node Handler for combat. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.char_hander = parent + self.drag = False + self.frame = open_rpg.get_component('frame') + self.myeditor = None + + + def on_drop(self,evt): + pass + + def on_rclick(self,evt): + pass + + def on_ldclick(self,evt): + return + + def on_html(self,evt): + html_str = self.tohtml() + wnd = http_html_window(self.frame.note,-1) + wnd.title = self.master_dom.getAttribute('name') + self.frame.add_panel(wnd) + wnd.SetPage(html_str) + + def get_design_panel(self,parent): + pass + + def get_use_panel(self,parent): + return self.get_design_panel(parent) + + def delete(self): + pass + +class dnd3ehp(combat_char_child): + """ Node Handler for hit points. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + combat_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.6009 + self.root.hp = self #a 1.6009 + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,hp_panel,"Hit Points") + wnd.title = "Hit Points" + return wnd + + def on_rclick( self, evt ): + chp = self.master_dom.getAttribute('current') + mhp = self.master_dom.getAttribute('max') + txt = '((HP: %s / %s))' % ( chp, mhp ) + self.chat.ParsePost( txt, True, True ) + + def tohtml(self): + html_str = "<table width=100% border=1 >" + html_str += "<tr BGCOLOR=#E9E9E9 ><th colspan=4>Hit Points</th></tr>" + html_str += "<tr><th>Max:</th>" + html_str += "<td>"+self.master_dom.getAttribute('max')+"</td>" + html_str += "<th>Current:</th>" + html_str += "<td>"+self.master_dom.getAttribute('current')+"</td>" + html_str += "</tr></table>" + return html_str + +class hp_panel(wx.Panel): + def __init__(self, parent, handler): + wx.Panel.__init__(self, parent, -1) + self.hparent = handler #a 1.5002 allow ability to run up tree. In this + #a 1.5002 case, we need the functional parent, not the invoking parent. + + pname = handler.master_dom.setAttribute("name", 'HitPoints') + self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap + self.master_dom = handler.master_dom + self.sizer.AddMany([ (wx.StaticText(self, -1, "HP Current:"), 0, + wx.ALIGN_CENTER_VERTICAL), + (wx.TextCtrl(self, HP_CUR, + self.master_dom.getAttribute('current')), 0, wx.EXPAND), + (wx.StaticText(self, -1, "HP Max:"), 0, wx.ALIGN_CENTER_VERTICAL), + (wx.TextCtrl(self, HP_MAX, self.master_dom.getAttribute('max')), + 0, wx.EXPAND), + ]) + self.sizer.AddGrowableCol(1) + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_TEXT, self.on_text, id=HP_MAX) + self.Bind(wx.EVT_TEXT, self.on_text, id=HP_CUR) + + def on_text(self,evt): + id = evt.GetId() + if id == HP_CUR: + self.master_dom.setAttribute('current',evt.GetString()) + elif id == HP_MAX: + self.master_dom.setAttribute('max',evt.GetString()) + + def on_size(self,evt): + s = self.GetClientSizeTuple() + self.sizer.SetDimension(0,0,s[0],s[1]) + +class dnd3eattacks(combat_char_child): + """ Node Handler for attacks. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + combat_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.attacks = self #a 1.6009 so others can find me. + self.mrFrame = [] #a 1.9001 + + #a 1.5012 start a1b + + self.updateFootNotes = False + self.updateFootNotes = False + self.html_str = "<html><body>" + self.html_str += ("<br> This character has weapons with no "+ + "footnotes. This program will "+ + "add footnotes to the weapons which have names that still match "+ + "the orginal names. If you have changed the weapon name, you "+ + "will see some weapons with a footnote of 'X', you will have "+ + "to either delete and re-add the weapon, or research "+ + "and add the correct footnotes for the weapon.\n"+ + "<br> Please be aware, that only the bow/sling footnote is "+ + "being used to affect changes to rolls; implemenation of other "+ + "footnotes to automaticly adjust rolls will be completed as "+ + "soon as time allows." + + "<br><br>Update to character:"+self.root.general.charName+ + "<br><br>"+ + """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > + <th width='80%'>Weapon Name</th><th>Added Footnote</th></tr>\n""") + self.temp_dom={} + #a 1.5012 end a1b + + node_list = self.master_dom.getElementsByTagName('melee') + self.melee = node_list[0] + node_list = self.master_dom.getElementsByTagName('ranged') + self.ranged = node_list[0] + self.refresh_weapons() # this causes self.weapons to be loaded. + + #a 1.5012 this whole if clause. + if self.updateFootNotes == True: + self.updateFootNotes = False + name = self.root.general.charName + self.html_str += "</table>" + self.html_str += "</body> </html> " + masterFrame = self.root.frame + + title = name+"'s weapons' update to have footnotes" + fnFrame = wx.Frame(masterFrame, -1, title) + fnFrame.panel = wx.html.HtmlWindow(fnFrame,-1) + fnFrame.panel.SetPage(self.html_str) + fnFrame.Show() + + #weaponsH = self.master_dom.getElementsByTagName('attacks') + #mark7 + + #a 1.9001 this whole method + def refreshMRdata(self): # refresh the data in the melee/ranged section + # of the attack chart. + # count backwards, maintains context despite "removes" + for i in range(len(self.mrFrame)-1,-1,-1): #a 1.9001 + x = self.mrFrame[i] + if x == None: + x.refreshMRdata() #a 1.9001 + else: + self.mrFrame.remove(x) + + def refresh_weapons(self): + self.weapons = {} + + tree = self.tree + icons = self.tree.icons + tree.CollapseAndReset(self.mytree_node) + node_list = self.master_dom.getElementsByTagName('weapon') + for n in node_list: + name = n.getAttribute('name') + fn = safeGetAttr(n,'fn') #a 1.5012 can be removed when + #a 1.5012 confident all characters in the world have footnotes. + #if self.updateFootNotes: + if fn == None:#a 1.5012 + self.updateFootNotes=True + self.updateFootN(n) #a 1.5012 + new_tree_node = tree.AppendItem( + self.mytree_node,name,icons['sword'],icons['sword']) + tree.SetPyData(new_tree_node,self) + self.weapons[name]=n + + def updateFootN(self,n):#a 1.5012 this whole function + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3eweapons.xml","r") + #tmp = open("c:\clh\codeSamples\sample1.xml","r") #a (debug) 1.5012 + self.temp_dom = xml.dom.minidom.parse(tmp) + + #self.temp_dom = parseXml_with_dlg(self,tmp.read()) + self.temp_dom = self.temp_dom._get_firstChild() + tmp.close() + nameF = n.getAttribute('name') + w_list = self.temp_dom.getElementsByTagName('weapon') + found = False + for w in w_list: + if nameF == w.getAttribute('name'): + found = True + fnN = safeGetAttr(n,'fn') + if fnN == None or fnN == 'None': + fnW = w.getAttribute('fn') + #print "weapon",nameF,"footnotes are updated to",fnW + self.html_str += ("<tr ALIGN='center'><td>"+nameF+"</td>"+ + "<td>"+fnW+"</td></tr>\n") + n.setAttribute('fn',fnW) + break + if not found: + self.html_str += ("<tr ALIGN='center'><td>"+nameF+" - Custom "+ + "Weapon, research "+ + "and update manually; setting footnote to indicate custom</td>"+ + "<td>"+'X'+"</td></tr>\n") + n.setAttribute('fn','X') + + + def get_mod(self,type='m'): + (base, base2, base3, base4, base5, base6, stat_mod, misc) \ + = self.get_attack_data(type) + return int(base + misc + int(stat_mod)) + + def get_attack_data(self,type='m'): + if type=='m' or type=='0': + stat = 'Str' #m was dnd_globals["stats"]['Str'] 1.5002 + temp = self.melee + else: + stat = 'Dex' #m was dnd_globals["stats"]['Dex'] 1.5002 + temp = self.ranged + stat_mod = -7 + stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 + #print "Big test - stat_mod",stat_mod #a (debug) 1.6000 + base = int(temp.getAttribute('base')) + base2 = int(temp.getAttribute('second')) + base3 = int(temp.getAttribute('third')) + base4 = int(temp.getAttribute('forth')) + base5 = int(temp.getAttribute('fifth')) + base6 = int(temp.getAttribute('sixth')) + misc = int(temp.getAttribute('misc')) + return (base, base2, base3, base4, base5, base6, stat_mod ,misc) + + def on_rclick(self,evt): + item = self.tree.GetSelection() + + name = self.tree.GetItemText(item) + if item == self.mytree_node: + #print "bail due to FUD" + return #a 1.6015 + #dnd3e_char_child.on_ldclick(self,evt)#d 1.6015 + #self.frame.add_panel(self.get_design_panel(self.frame.note)) + else: + #print "entering attack phase" + mod = int(self.weapons[name].getAttribute('mod')) + wepMod = mod #a 1.5008 + footNotes = safeGetAttr(self.weapons[name],'fn','') + cat = self.weapons[name].getAttribute('category') #a1.6001 + result = split(cat,"-",2) #a 1.6001 + if len(result) < 2: #a 1.6021 this if & else + print "warning: 1.6002 unable to interpret weapon category" + print "format 'type weapon-[Range|Melee]', probably missing" + print "the hyphen. Assuming Melee" + print "weapon name: ",name + tres="Melee" + else: + tres=result[1] + #print "print FootNotes,tres",footNotes,tres + if tres == 'Melee': #a 1.6001 #m 1.6022 use of tres here and... + #if self.weapons[name].getAttribute('range') == '0':#d 1.6001 + rangeOrMelee = 'm' #a 1.5008 code demote for next comment block + elif tres == 'Ranged': #m 1.6001 (was just else) #m 1.6022 here + rangeOrMelee = 'r' #a 1.5008 + else:#a 1.6001 add this whole else clause. + print "warning: 1.6001 unable to interpret weapon category" + print "treating weapon as Melee, please correct xml" + print "weapon name:",name + rangeOrMelee ='m' + mod = mod + self.get_mod(rangeOrMelee) #a 1.5008 + chat = self.chat + dmg = self.weapons[name].getAttribute('damage') + + #a 1.6003 start code fix instance a + result = split(dmg,"/",2) + dmg = result[0] + #print "1.6003 check:dmg",dmg,";result",result + #o currently, only picking out dmg; rest are simply ignored. + #o May be usefull + #o later for two weapon attack correction. + #a 1.6003 end code fix instance a + + monkLvl = self.root.classes.get_class_lvl('Monk') # a 1.5002 + #print "monkLvl",monkLvl #a (debug) 1.5002 + # monkLvl = dnd_globals["class"]["lvl"] #d 1.5002 + if dmg == "Monk Med": + 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 + return #a 1.5009 + else: #a 1.5009 + lvl=int(monkLvl) + if lvl <= 3: #m 1.6022 reversed the order of checks. + dmg = "1d6" + elif lvl <= 7: + dmg = "1d8" + elif lvl <= 11: + dmg = "1d10" + elif lvl <= 15: + dmg = "2d6" + elif lvl <= 19: + dmg = "2d8" + elif lvl <= 20: + dmg = "2d10" + if dmg == "Monk Small": + 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 + return #a 1.5009 + else: #a 1.5009 + lvl=int(monkLvl) + if lvl <= 3: #m 1.6022 reversed the order of the checks + dmg = "1d4" + elif lvl <= 7: + dmg = "1d6" + elif lvl <= 11: + dmg = "1d8" + elif lvl <= 15: + dmg = "1d10" + elif lvl <= 20: + dmg = "2d6" + flu = '' + #print "adjusted weapon damage is:",dmg + #o 1.5007 str bow + #o 1.5011 start looking about here str dam bonus missed for thrown? + #o 1.5012 start looking about here str penalty missed for bow/sling? + #o 1.5013 off-hand attacks.? dam and all affects? + str_mod = self.root.abilities.get_mod('Str') #a 1.5007,11,12,13 + if rangeOrMelee == 'r': #a 1.5008 + #if off_hand == True then stat_mod = stat_mod/2 #o 1.5013 + #c 1.5007 ranged weapons normally get no str mod + if find(footNotes,'b') > -1:#a 1.5012 if it's a bow + if str_mod >= 0: #a 1.5012 never a str bonus + str_mod = 0 #a 1.5012 penalty, + else: #a 1.5012 if appropriate + str_mod = 0 + # c 1.5007 (must adjust for str bows later and thown weapons) + #o 1.5007 include + for str bows + #o 1.5012 include any str penalty for bows/slings. + mod2 = "" #a 1.5007,11-13 + if str_mod >= 0: #1.6 tidy up code. + mod2 = "+" #1.6 tidy up code. + aStrengthMod = mod2 + str(str_mod) #a 1.5008 applicable strength mod + + #if name == "Flurry of Blows(Monk Med)": #d 1.6012 + if find(name ,"Flurry of Blows") > -1: #a 1.6012 + flu = '-2' + + (base, base2, base3, base4, base5, base6, stat_mod, misc)\ + = self.get_attack_data(rangeOrMelee) #a 1.5008 + self.sendRoll(base ,stat_mod,misc,wepMod,name,flu,dmg, + aStrengthMod,'',True,rollAnyWay=True) + if flu != '': + self.sendRoll(base ,stat_mod,misc,wepMod,name,flu,dmg, + aStrengthMod) #a 1.6021 + + self.sendRoll(base2,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod) + self.sendRoll(base3,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod) + self.sendRoll(base4,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod) + self.sendRoll(base5,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod) + self.sendRoll(base6,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod) + + + def sendRoll(self,base,stat_mod,misc,wepMod,name,flu,dmg,aStrengthMod, + spacer="",pname=False,rollAnyWay=False): + if base != 0 or rollAnyWay: + base = base + int(stat_mod) + misc + wepMod #m 1.5008 + if base >= 0: + mod1 = "+" + else: + mod1 = "" + txt = '%s ' % (spacer) + txt += '%s Attack Roll: <b>[1d20%s%s%s]</b>' % (name, mod1, base, flu) + txt += ' ===> Damage: <b>[%s%s]</b>' % (dmg, aStrengthMod) + self.chat.ParsePost( txt, True, True ) + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,attack_panel,"Attacks") + wnd.title = "Attacks" + return wnd + + def tohtml(self): + melee = self.get_attack_data('m') + ranged = self.get_attack_data('r') + html_str = ("""<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 >"""+ + "<th>Attack</th><th>Total</th><th >Base</th>"+ + "<th>Abil</th><th>Misc</th></tr>") + html_str += "<tr ALIGN='center' ><th >Melee:</th>" + html_str += "<td>"+str(melee[0]+melee[1]+melee[2])+"</td>" + html_str += "<td>"+str(melee[0])+"</td>" + html_str += "<td>"+str(melee[1])+"</td>" + html_str += "<td>"+str(melee[2])+"</td></tr>" + + html_str += "<tr ALIGN='center' ><th >Ranged:</th>" + html_str += "<td>"+str(ranged[0]+ranged[1]+ranged[2])+"</td>" + html_str += "<td>"+str(ranged[0])+"</td>" + html_str += "<td>"+str(ranged[1])+"</td>" + html_str += "<td>"+str(ranged[2])+"</td></tr></table>" + + n_list = self.master_dom.getElementsByTagName('weapon') + for n in n_list: + mod = n.getAttribute('mod') + if mod >= 0: + mod1 = "+" + else: + mod1 = "" + ran = n.getAttribute('range') + total = str(int(mod) + self.get_mod(ran)) + html_str += """<P><table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > + <th colspan=2>Weapon</th> + <th>Attack</th><th >Damage</th><th>Critical</th></tr>""" + html_str += "<tr ALIGN='center' ><td colspan=2>" + html_str += n.getAttribute('name')+"</td><td>"+total+"</td>" + html_str += "<td>"+n.getAttribute('damage')+"</td><td>" + html_str += n.getAttribute('critical')+"</td></tr>" + html_str += """<tr BGCOLOR=#E9E9E9 ><th>Range</th><th>Weight</th> + <th>Type</th><th>Size</th><th>Misc Mod</th></tr>""" + html_str += "<tr ALIGN='center'><td>"+ran+"</td><td>" + html_str += n.getAttribute('weight')+"</td>" + html_str += "<td>"+n.getAttribute('type')+"</td><td>" + html_str += n.getAttribute('size')+"</td>" + html_str += '<td>%s%s</td></tr>' % (mod1, mod) + #a 1.5012 add next two lines to pretty print footnotes. + html_str += """<tr><th BGCOLOR=#E9E9E9 colspan=2>Footnotes:</th>""" + html_str += "<th colspan=3>"+safeGetAttr(n,'fn','')+"</th></tr>" + html_str += '</table>' + return html_str + +class attack_grid(wx.grid.Grid): + """grid for attacks""" + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Melee') + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 we need the functional parent, not the invoking parent. + + wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + + self.root = getRoot(self) #a 1.9001 + self.parent = parent + self.handler = handler + self.rows = (self.handler.melee,self.handler.ranged) + self.CreateGrid(2,10) + self.SetRowLabelSize(0) + col_names = ['Type','base','base 2','base 3','base 4','base 5', + 'base 6','abil','misc','Total'] + for i in range(len(col_names)): + self.SetColLabelValue(i,col_names[i]) + self.SetCellValue(0,0,"Melee") + self.SetCellValue(1,0,"Ranged") + self.refresh_data() + self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + #print "looking for containing frame" + + #a 1.9001 remainder of code in this method. + climber = parent + nameNode = climber.GetClassName() + while nameNode != 'wxFrame': + climber = climber.parent + nameNode = climber.GetClassName() + masterFrame=climber + masterFrame.refreshMRdata=self.refresh_data + #print getmembers(masterFrame) + + handler.mrFrame.append(masterFrame) + + #print "masterFrame=",masterFrame + #print "mr.Show=",masterFrame.Show() + #print "mf.GetName",masterFrame.GetName() + #print "mf.GetClassName",masterFrame.GetClassName() + #print "mf.GetId",masterFrame.GetId() + #print "mf.GetLabel",masterFrame.GetLabel() + #print "mf.GetHandle",masterFrame.GetHandle() + #print "mf.GetParent",masterFrame.GetParent() + # here, GetParent consistent returns the master frame of the app. + #print "mf.GetGParent",masterFrame.GetGrandParent() #here, always None + #print "mf.GetTitle",masterFrame.GetTitle() + #print "mf.IsEnabled",masterFrame.IsEnabled() + #print "mf.IsShown",masterFrame.IsShown() + #print "mf.IsTopLevel",masterFrame.IsTopLevel() + #print "self.frame=",self.frame + + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.GetCellValue(row,col) + try: + int(value) + if col==1: + self.rows[row].setAttribute('base',value) + elif col==2: + self.rows[row].setAttribute('second',value) + elif col==3: + self.rows[row].setAttribute('third',value) + elif col==4: + self.rows[row].setAttribute('forth',value) + elif col==5: + self.rows[row].setAttribute('fifth',value) + elif col==6: + self.rows[row].setAttribute('sixth',value) + elif col==8: + self.rows[row].setAttribute('misc',value) + #print "row:",row,"value",value,self.rows[row] + self.parent.refresh_data() + except: + self.SetCellValue(row,col,"0") + + def refresh_data(self): + + melee = self.handler.get_attack_data('m') + ranged = self.handler.get_attack_data('r') + tmelee = int(melee[0]) + int(melee[6]) + int(melee[7]) + tranged = int(ranged[0]) + int(ranged[6]) + int(ranged[7]) + # for i in range(0,7): #d 1.5005 + for i in range(0,8): #a 1.5005 + self.SetCellValue(0,i+1,str(melee[i])) + self.SetCellValue(1,i+1,str(ranged[i])) + self.SetCellValue(0,9,str(tmelee)) + self.SetCellValue(1,9,str(tranged)) + self.SetReadOnly(0,0) + self.SetReadOnly(1,0) + self.SetReadOnly(0,7) + self.SetReadOnly(1,7) + self.SetReadOnly(0,9) + self.SetReadOnly(1,9) + + + def on_size(self,evt): + (w,h) = self.GetClientSizeTuple() + cols = self.GetNumberCols() + col_w = w/(cols+1) + self.SetColSize(0,col_w*2) + for i in range(1,cols): + self.SetColSize(i,col_w) + evt.Skip() + self.Refresh() + +class weapon_panel(wx.Panel): + def __init__(self, parent, handler): + self.hparent = handler #a 1.5012 + self.root = getRoot(self) + + pname = handler.master_dom.setAttribute("name", 'Weapons') + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer2 = wx.BoxSizer(wx.HORIZONTAL) + sizer2.Add(wx.Button(self, 10, "Remove Weapon"), 0, wx.EXPAND) + sizer2.Add(wx.Size(10,10)) + sizer2.Add(wx.Button(self, 20, "Add Weapon"), 0, wx.EXPAND) + + sizer.Add(sizer2, 0, wx.EXPAND) + sizer.Add(wx.StaticText(self, -1, "Right click a weapon's footnote to see what the footnotes mean."),0, wx.EXPAND)#a 1.5012 + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + self.sizer2 = sizer2 + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) + self.Bind(wx.EVT_BUTTON, self.on_add, id=20) + self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.on_gridRclick)#a 1.5012 + + n_list = handler.master_dom.getElementsByTagName('weapon') + self.n_list = n_list + self.master_dom = handler.master_dom + self.handler = handler + #trash=input("weapon panel init colnames") + self.colAttr = ['name','damage','mod','critical','type','weight', + 'range','size','Total','fn', 'comment'] #a 1.5012 + col_names = ['Name','Damage','To hit\nmod','Critical','Type','Weight', + 'Range','Size','Total','Foot\nnotes','Comment'] #a 1.5012 + gridColCount=len(col_names)#a 1.5012 + self.grid.CreateGrid(len(n_list),gridColCount,1) #a 1.5012 + #self.grid.CreateGrid(len(n_list),9,1) #d 1.5012 + self.grid.SetRowLabelSize(0) + #col_names = ['Name','damage','mod','critical','type','weight','range', 'size','Total'] #d 1.5012 + #for i in range(len(col_names)): #d 1.5012 + for i in range(gridColCount): #a 1.5012 + self.grid.SetColLabelValue(i,col_names[i]) + self.refresh_data() + self.temp_dom = None + + + #mark4 + #a 1.5012 add entire method. + def on_gridRclick(self,evt): + #print "weapon_panel, on_rclick: self,evt",self,evt + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + #print "wp, on rclick,grid row,col,value",row,col,value + if col == 9 and value != 'None': + n = self.n_list[row] + name = n.getAttribute('name') + #print "we want a panel!" + handler = self.hparent + #print "handler:",handler + # A handler is a node, and nodes have a reference to + # the master frame + masterFrame = handler.frame + #print "masterFrame:",masterFrame + title = name+"'s Special Weapon Characteristics" + fnFrame = wx.Frame(masterFrame, -1, title) + fnFrame.panel = wx.html.HtmlWindow(fnFrame,-1) + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+ + "dnd3eweapons.xml","r") + #tmp = open("c:\clh\codeSamples\sample1.xml","r") + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('f') # the footnotes + #print "weapon_panel - on_rclick f_list",f_list#a 1.6 + n = self.n_list[row] + name = n.getAttribute('name') + footnotes = n.getAttribute('fn') + html_str = "<html><body>" + html_str += """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > + <th width='10%'>Note</th><th>Description</th></tr>\n""" + #print "rclick,name,fn",name,footnotes + if footnotes == "": + html_str += "<tr ALIGN='center'><td></td>" + html_str += " <td>This weapon has no footnotes</td></tr>" + for i in range(len(footnotes)): + aNote=footnotes[i] + found=False + for f in f_list: + if f.getAttribute('mark') == aNote: + found=True + text=f.getAttribute('txt') + html_str += ("<tr ALIGN='center'><td>"+aNote+"</td>"+ + "<td>"+text+"</td></tr>\n") + if not found: + html_str += ("<tr ALIGN='center'><td>"+aNote+"</td>"+ + "<td>is not a recognized footnote</td></tr>\n") + + html_str += "</table>" + html_str += "</body> </html> " + + #print html_str + fnFrame.panel.SetPage(html_str) + fnFrame.Show() + return + pass + + + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + if col == 2 and not int(value): # special case for mod, demoted + value = "0" #a 5.012 demoted + self.n_list[row].setAttribute('mod',value) # a 5.012 demoted + if not (col == 9 and value == "None" and + self.n_list[row].getAttribute('fn') == "None" + ): #a 5.012 special case for footnotes + self.n_list[row].setAttribute(self.colAttr[col],value)#a 5.012 + #print "cell change",row,col,value + #if col == 0:#d 5.012 use of colAttr removed need for this. + # self.n_list[row].setAttribute('name',value) #d 5.012 + #elif col == 2: #d 5.012 + # try:#d 5.012 simplifying... remove this block. + # int(value) + # self.n_list[row].setAttribute('mod',value) + # #self.refresh_row(row) #d 5.012 did nothing. + # except: + # value = "0" + # self.n_list[row].setAttribute('mod',value) + #else: #d 5.012 demoted self.n set. + # self.n_list[row].setAttribute(self.grid.GetColLabelValue(col),value) + + + def refresh_row(self,i): + n = self.n_list[i] + fn = n.getAttribute('fn') + #print "fn=",fn + name = n.getAttribute('name') + mod = n.getAttribute('mod') + ran = n.getAttribute('range') + total = str(int(mod) + self.handler.get_mod(ran)) + self.grid.SetCellValue(i,0,name) + self.grid.SetCellValue(i,1,n.getAttribute('damage')) + self.grid.SetCellValue(i,2,mod) + self.grid.SetCellValue(i,3,n.getAttribute('critical')) + self.grid.SetCellValue(i,4,n.getAttribute('type')) + self.grid.SetCellValue(i,5,n.getAttribute('weight')) + self.grid.SetCellValue(i,6,ran) + self.grid.SetCellValue(i,7,n.getAttribute('size') ) + self.grid.SetCellValue(i,8,total) + self.grid.SetCellValue(i,9,safeGetAttr(n,'fn','None')) #a 1.5012 + self.grid.SetCellValue(i,10,safeGetAttr(n,'comment','')) #a 1.5012 + #fn=safeGetAttr(n,'fn','None') #a (debug) 1.5012 + #print "fn ",fn,"<" #a (debug) 1.5012 + #o 1.5012 original damage vs what someone has changed it to. + + self.grid.SetReadOnly(i,8) + + def on_remove(self,evt): #o 1.6011 correcting wrongful deletion + rows = self.grid.GetNumberRows() + #for i in range(rows): #d 1.6011 do it backwards, + for i in range(rows-1,-1,-1): #a 1.6011 or you lose context + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + self.n_list = self.master_dom.getElementsByTagName('weapon') + self.handler.refresh_weapons() + + def on_add(self,evt): + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3eweapons.xml","r") + #tmp = open("c:\clh\codeSamples\sample1.xml","r") #a (debug) 1.5012 + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('weapon') + opts = [] + #print "weapon_panel - on_add f_list",f_list#a 1.6 + for f in f_list: + opts.append(f.getAttribute('name')) + dlg = wx.SingleChoiceDialog(self,'Choose Weapon','Weapon List',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + #print f_list[i] # DOM Element: weapon. + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + #print self.grid.AppendRows # a bound method of wxGrid + self.grid.AppendRows(1) + self.n_list = self.master_dom.getElementsByTagName('weapon') + #print "self.n_list",self.n_list # list of DOM weapons + self.refresh_row(self.grid.GetNumberRows()-1) + self.handler.refresh_weapons() + dlg.Destroy() + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-40) + self.sizer.SetDimension(0,s[1]-40,s[0],25) + self.sizer2.SetDimension(0,s[1]-15,s[0],15) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols+1) + self.grid.SetColSize(0,col_w*2) + for i in range(1,cols): + self.grid.SetColSize(i,col_w) + + def refresh_data(self): + + for i in range(len(self.n_list)): + self.refresh_row(i) + + +class attack_panel(wx.Panel): + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Melee') + self.parent = parent #a 1.9001 + + wx.Panel.__init__(self, parent, -1) + + self.a_grid = attack_grid(self, handler) + self.w_panel = weapon_panel(self, handler) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.a_grid, 1, wx.EXPAND) + self.sizer.Add(self.w_panel, 2, wx.EXPAND) + self.Bind(wx.EVT_SIZE, self.on_size) + + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.sizer.SetDimension(0,0,s[0],s[1]) + + def refresh_data(self): + + self.w_panel.refresh_data() + self.a_grid.refresh_data() + + +class dnd3earmor(combat_char_child): + """ Node Handler for ac. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + combat_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.ac = self #a 1.6009 + + def get_spell_failure(self): + return self.get_total('spellfailure') + + def get_total_weight(self): + return self.get_total('weight') + + def get_check_pen(self): + return self.get_total('checkpenalty') + + def get_armor_class(self): + ac_total = 10 + + ac_total += self.get_total('bonus') + #m 1.5009 change to hardcode dex, was incorrect gv "stat" + dex_mod = self.root.abilities.get_mod('Dex')#m 1.5009 hardcode dex + max_dex = self.get_max_dex() + if dex_mod < max_dex: + ac_total += dex_mod + else: + ac_total += max_dex + return ac_total + + def get_max_dex(self): + armor_list = self.master_dom.getElementsByTagName('armor') + dex = 10 + for a in armor_list: + temp = int(a.getAttribute("maxdex")) + if temp < dex: + dex = temp + return dex + + def get_total(self,attr): + armor_list = self.master_dom.getElementsByTagName('armor') + total = 0 + for a in armor_list: + total += int(a.getAttribute(attr)) + return total + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,ac_panel,"Armor") + wnd.title = "Armor" + return wnd + + def on_rclick( self, evt ): + 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 ) + + def tohtml(self): + html_str = """<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > + <th>AC</th><th>Check Penalty</th><th >Spell Failure</th> + <th>Max Dex</th><th>Total Weight</th></tr>""" + html_str += "<tr ALIGN='center' >" + html_str += "<td>"+str(self.get_armor_class())+"</td>" + html_str += "<td>"+str(self.get_check_pen())+"</td>" + html_str += "<td>"+str(self.get_spell_failure())+"</td>" + html_str += "<td>"+str(self.get_max_dex())+"</td>" + html_str += "<td>"+str(self.get_total_weight())+"</td></tr></table>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += """<P><table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > + <th colspan=3>Armor</th><th>Type</th><th >Bonus</th></tr>""" + html_str += "<tr ALIGN='center' >" + html_str += "<td colspan=3>"+n.getAttribute('name')+"</td>" + html_str += "<td>"+n.getAttribute('type')+"</td>" + html_str += "<td>"+n.getAttribute('bonus')+"</td></tr>" + html_str += """<tr BGCOLOR=#E9E9E9 >""" + html_str += "<th>Check Penalty</th><th>Spell Failure</th>" + html_str += "<th>Max Dex</th><th>Speed</th><th>Weight</th></tr>" + html_str += "<tr ALIGN='center'>" + html_str += "<td>"+n.getAttribute('checkpenalty')+"</td>" + html_str += "<td>"+n.getAttribute('spellfailure')+"</td>" + html_str += "<td>"+n.getAttribute('maxdex')+"</td>" + html_str += "<td>"+n.getAttribute('speed')+"</td>" + html_str += "<td>"+n.getAttribute('weight')+"</td></tr></table>" + return html_str + + +class ac_panel(wx.Panel): + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Armor') + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 we need the functional parent, not the invoking parent. + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Armor"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Armor"), 1, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) + self.Bind(wx.EVT_BUTTON, self.on_add, id=20) + self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + self.master_dom = handler.master_dom + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + col_names = ['Armor','bonus','maxdex','cp','sf','weight','speed','type'] + self.grid.CreateGrid(len(n_list),len(col_names),1) + self.grid.SetRowLabelSize(0) + for i in range(len(col_names)): + self.grid.SetColLabelValue(i,col_names[i]) + self.atts =['name','bonus','maxdex','checkpenalty', + 'spellfailure','weight','speed','type'] + for i in range(len(n_list)): + self.refresh_row(i) + self.temp_dom = None + + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + if col >= 1 and col <= 5: + try: + int(value) + self.n_list[row].setAttribute(self.atts[col],value) + except: + self.grid.SetCellValue(row,col,"0") + else: + self.n_list[row].setAttribute(self.atts[col],value) + + def refresh_row(self,i): + n = self.n_list[i] + + for y in range(len(self.atts)): + self.grid.SetCellValue(i,y,n.getAttribute(self.atts[y])) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3earmor.xml","r") + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('armor') + opts = [] + for f in f_list: + opts.append(f.getAttribute('name')) + dlg = wx.SingleChoiceDialog(self,'Choose Armor:','Armor List',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.refresh_row(self.grid.GetNumberRows()-1) + dlg.Destroy() + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols+2) + self.grid.SetColSize(0,col_w*3) + for i in range(1,cols): + self.grid.SetColSize(i,col_w) + + +class dnd3esnp(dnd3e_char_child): + """ Node Handler for power points. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + dnd3e_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + + + self.frame = open_rpg.get_component('frame') + self.child_handlers = {} + self.new_child_handler('spells','Spells',dnd3espells,'book') + self.new_child_handler('divine','Divine Spells',dnd3edivine,'book') + self.new_child_handler('powers','Powers',dnd3epowers,'book') + self.new_child_handler('pp','Power Points',dnd3epp,'gear') + self.myeditor = None + + def new_child_handler(self,tag,text,handler_class,icon='gear'): + node_list = self.master_dom.getElementsByTagName(tag) + tree = self.tree + i = self.tree.icons[icon] + new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) + handler = handler_class(node_list[0],new_tree_node,self) + tree.SetPyData(new_tree_node,handler) + self.child_handlers[tag] = handler + + def get_design_panel(self,parent): + return tabbed_panel(parent,self,1) + + def get_use_panel(self,parent): + return tabbed_panel(parent,self,2) + +# def set_char_pp(self,attr,evl): #d 1.5002 doesn't seem to be used, but +# dnd_globals["pp"][attr] = evl #d 1.5002 uses dnd_globals, so tossing. + + +# def get_char_pp( self, attr ): #d 1.5002 doesn't seem to be used, but +# return dnd_globals["pp"][attr] #d 1.5002 doesn't seem to be used, but + +class snp_char_child(node_handler): + """ Node Handler for skill. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + node_handler.__init__(self,xml_dom,tree_node) + self.char_hander = parent + self.drag = False + self.frame = open_rpg.get_component('frame') + self.myeditor = None + + + + def on_drop(self,evt): + pass + + def on_rclick(self,evt): + pass + + def on_ldclick(self,evt): + return + + def on_html(self,evt): + html_str = self.tohtml() + wnd = http_html_window(self.frame.note,-1) + wnd.title = self.master_dom.getAttribute('name') + self.frame.add_panel(wnd) + wnd.SetPage(html_str) + + def get_design_panel(self,parent): + pass + + def get_use_panel(self,parent): + return self.get_design_panel(parent) + + def delete(self): + pass + + +class dnd3espells(snp_char_child): + """ Node Handler for classes. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + snp_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.spells = self #a 1.6009 + + + node_list = self.master_dom.getElementsByTagName( 'spell' ) + self.spells = {} + tree = self.tree + icons = self.tree.icons + for n in node_list: + name = n.getAttribute('name') + self.spells[ name ] = n + new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] ) + tree.SetPyData( new_tree_node, self ) + + def on_rclick( self, evt ): + item = self.tree.GetSelection() + name = self.tree.GetItemText( item ) + if item == self.mytree_node: + dnd3e_char_child.on_ldclick( self, evt ) + else: + level = self.spells[ name ].getAttribute( 'level' ) + descr = self.spells[ name ].getAttribute( 'desc' ) + use = self.spells[ name ].getAttribute( 'used' ) + memrz = self.spells[ name ].getAttribute( 'memrz' ) + use += '+1' + charNameL=self.root.general.charName #a 1.5002 + left = eval( '%s - ( %s )' % ( memrz, use ) ) + 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."' % ( dnd_globals["gen"]["Name"], name )##d 1.5002 + txt +='"Please rest so I can cast more."' % ( charNameL, name ) #a 1.5002 + self.chat.ParsePost( txt, True, False ) + else: + #txt = '%s casts %s ( level %s, "%s" )' % ( dnd_globals["gen"]["Name"], name, level, descr )#d 1.5002 + txt = '%s casts %s ( level %s, "%s" )' % ( charNameL, name, level, descr )#a f 1.5002 + self.chat.ParsePost( txt, True, False ) + s = '' + if left != 1: + s = 's' + #txt = '%s can cast %s %d more time%s' % ( dnd_globals["gen"]["Name"], name, left, s )#d 1.5002 + txt = '%s can cast %s %d more time%s' % ( charNameL, name, left, s ) #a 1.5002 + self.chat.ParsePost( txt, False, False ) + self.spells[ name ].setAttribute( 'used', `eval( use )` ) + + def refresh_spells(self): + self.spells = {} + tree = self.tree + icons = self.tree.icons + tree.CollapseAndReset(self.mytree_node) + node_list = self.master_dom.getElementsByTagName('spell') + for n in node_list: + name = n.getAttribute('name') + new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear']) + tree.SetPyData(new_tree_node,self) + self.spells[name]=n + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,spells_panel,"Spells") + wnd.title = "Spells" + return wnd + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Arcane Spells</th></tr><tr><td><br>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += "(" + n.getAttribute('level') + ") " + n.getAttribute('name')+ ", " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + + def get_char_lvl( self, attr ): + return self.char_hander.get_char_lvl(attr) + +class spells_panel(wx.Panel): + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Arcane Spells') + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.handler = handler + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Spell"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Spell"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 30, "Refresh Spells"), 1, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + 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) + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + self.master_dom = handler.master_dom + self.grid.CreateGrid(len(n_list),4,1) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelValue(0,"No.") + self.grid.SetColLabelValue(1,"Lvl") + self.grid.SetColLabelValue(2,"Spell") + self.grid.SetColLabelValue(3,"Desc") + for i in range(len(n_list)): + self.refresh_row(i) + self.temp_dom = None + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + if col == 0: + self.n_list[row].setAttribute('memrz',value) + + + def refresh_row(self,i): + spell = self.n_list[i] + + memrz = spell.getAttribute('memrz') + name = spell.getAttribute('name') + type = spell.getAttribute('desc') + level = spell.getAttribute('level') + self.grid.SetCellValue(i,0,memrz) + 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,1) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3espells.xml","r") + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('spell') + opts = [] + #lvl = int(dnd3e_char_child.get_char_lvl('level')) + #castlvl = eval('%s/2' % (lvl)) + for f in f_list: + spelllvl = f.getAttribute('level') + #if spelllvl <= "1": + # opts.append("(" + f.getAttribute('level') + ")" + f.getAttribute('name')) + #else: + # if eval('%d >= %s' %(castlvl, spelllvl)): + opts.append("(" + f.getAttribute('level') + ")" + f.getAttribute('name')) + dlg = wx.SingleChoiceDialog(self,'Choose Spell','Spells',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.n_list = self.master_dom.getElementsByTagName('spell') + self.refresh_row(self.grid.GetNumberRows()-1) + self.handler.refresh_spells() + dlg.Destroy() + + def on_refresh_spells( self, evt ): + f_list = self.master_dom.getElementsByTagName('spell') + + for spell in f_list: + spell.setAttribute( 'used', '0' ) + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols) + for i in range(0,cols): + self.grid.SetColSize(i,col_w) + self.grid.SetColSize(0,w * 0.10) + self.grid.SetColSize(1,w * 0.10) + self.grid.SetColSize(2,w * 0.30) + self.grid.SetColSize(3,w * 0.50) + + def refresh_data(self): + for i in range(len(self.n_list)): + self.refresh_row(i) + +class dnd3edivine(snp_char_child): + """ Node Handler for classes. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + snp_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.divine = self #a 1.6009 + + + node_list = self.master_dom.getElementsByTagName( 'gift' ) + self.spells = {} + tree = self.tree + icons = self.tree.icons + for n in node_list: + name = n.getAttribute('name') + self.spells[ name ] = n + new_tree_node = tree.AppendItem( self.mytree_node, name, icons['flask'], icons['flask'] ) + tree.SetPyData( new_tree_node, self ) + + def on_rclick( self, evt ): + charNameL=self.root.general.charName #a f 1.5002 + item = self.tree.GetSelection() + name = self.tree.GetItemText( item ) + if item == self.mytree_node: + dnd3e_char_child.on_ldclick( self, evt ) + else: + level = self.spells[ name ].getAttribute( 'level' ) + descr = self.spells[ name ].getAttribute( 'desc' ) + use = self.spells[ name ].getAttribute( 'used' ) + memrz = self.spells[ name ].getAttribute( 'memrz' ) + use += '+1' + left = eval( '%s - ( %s )' % ( memrz, use ) ) + 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 + #txt += "Please rest so I can cast more."' % ( dnd_globals["gen"]["Name"], name ) #d 1.5002 + self.chat.ParsePost( txt, True, False ) + else: + #txt = '%s casts %s ( level %s, "%s" )' % ( dnd_globals["gen"]["Name"], name, level, descr ) #d 1.5002 + txt = '%s casts %s ( level %s, "%s" )' % ( charNameL, name, level, descr ) #a 5002 + self.chat.ParsePost( txt, True, False ) + s = '' + if left != 1: + s = 's' + #txt = '%s can cast %s %d more time%s' % ( dnd_globals["gen"]["Name"], name, left, s ) #d 1.5002 + txt = '%s can cast %s %d more time%s' % ( charNameL, name, left, s ) #a 1.5002 + self.chat.ParsePost( txt, False, False ) + self.spells[ name ].setAttribute( 'used', `eval( use )` ) + + def refresh_spells(self): + self.spells = {} + tree = self.tree + icons = self.tree.icons + tree.CollapseAndReset(self.mytree_node) + + node_list = self.master_dom.getElementsByTagName('gift') + for n in node_list: + name = n.getAttribute('name') + new_tree_node = tree.AppendItem(self.mytree_node,name,icons['flask'],icons['flask']) + tree.SetPyData(new_tree_node,self) + self.spells[name]=n + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,divine_panel,"Spells") + wnd.title = "Spells" + return wnd + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Divine Spells</th></tr><tr><td><br>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += "(" + n.getAttribute('level') + ") " + n.getAttribute('name')+ ", " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + + def get_char_lvl( self, attr ): + return self.char_hander.get_char_lvl(attr) + +class divine_panel(wx.Panel): + def __init__(self, parent, handler): + pname = handler.master_dom.setAttribute("name", 'Divine Spells') + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 in this case, we need the functional parent, not the invoking parent. + + wx.Panel.__init__(self, parent, -1) + self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.handler = handler + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Spell"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Spell"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 30, "Refresh Spells"), 1, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + 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) + + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + self.master_dom = handler.master_dom + self.grid.CreateGrid(len(n_list),4,1) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelValue(0,"No.") + self.grid.SetColLabelValue(1,"Lvl") + self.grid.SetColLabelValue(2,"Spell") + self.grid.SetColLabelValue(3,"Desc") + for i in range(len(n_list)): + self.refresh_row(i) + self.temp_dom = None + + def on_cell_change(self,evt): + row = evt.GetRow() + + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + if col == 0: + self.n_list[row].setAttribute('memrz',value) + + + def refresh_row(self,i): + spell = self.n_list[i] + + memrz = spell.getAttribute('memrz') + name = spell.getAttribute('name') + type = spell.getAttribute('desc') + level = spell.getAttribute('level') + self.grid.SetCellValue(i,0,memrz) + 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,1) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3edivine.xml","r") + + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('gift') + opts = [] + #lvl = int(dnd3e_char_child.get_char_lvl('level')) + #castlvl = lvl / 2 + for f in f_list: + spelllvl = f.getAttribute('level') + #if spelllvl <= "1": + # opts.append("(" + f.getAttribute('level') + ")" + f.getAttribute('name')) + #else: + # if eval('%d >= %s' %(castlvl, spelllvl)): + opts.append("(" + f.getAttribute('level') + ")" + f.getAttribute('name')) + dlg = wx.SingleChoiceDialog(self,'Choose Spell','Spells',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.n_list = self.master_dom.getElementsByTagName('gift') + self.refresh_row(self.grid.GetNumberRows()-1) + self.handler.refresh_spells() + dlg.Destroy() + + def on_refresh_spells( self, evt ): + f_list = self.master_dom.getElementsByTagName('gift') + for spell in f_list: + spell.setAttribute( 'used', '0' ) + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols) + for i in range(0,cols): + self.grid.SetColSize(i,col_w) + self.grid.SetColSize(0,w * 0.10) + self.grid.SetColSize(1,w * 0.10) + self.grid.SetColSize(2,w * 0.30) + self.grid.SetColSize(3,w * 0.50) + + def refresh_data(self): + + for i in range(len(self.n_list)): + self.refresh_row(i) + + +class dnd3epowers(snp_char_child): + """ Node Handler for classes. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + snp_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) #a 1.5002 + self.root.powers = self #a 1.6009 + + node_list = self.master_dom.getElementsByTagName( 'power' ) + self.powers = {} + tree = self.tree + icons = self.tree.icons + for n in node_list: + name = n.getAttribute('name') + self.powers[ name ] = n + new_tree_node = tree.AppendItem( self.mytree_node, name, + icons['gear'], icons['gear'] ) + tree.SetPyData( new_tree_node, self ) + + def on_rclick( self, evt ): + charNameL = self.root.general.charName #a f 1.5002 + + item = self.tree.GetSelection() + name = self.tree.GetItemText( item ) + charNameL = self.root.general.charName #a 1.5002 + if item == self.mytree_node: + dnd3e_char_child.on_ldclick( self, evt ) + else: + level = int(self.powers[ name ].getAttribute( 'level' )) + descr = self.powers[ name ].getAttribute( 'desc' ) + #use can be removed -mgt + #use = self.powers[ name ].getAttribute( 'used' ) + points = self.powers[ name ].getAttribute( 'point' ) + #cpp and fre are strings without the eval -mgt + cpp = eval(self.root.pp.get_char_pp('current1')) #a 1.5002 + fre = eval(self.root.pp.get_char_pp('free')) #a 1.5002 + if level == 0 and fre > 0: + left = eval('%s - ( %s )' % ( fre, points )) + numcast = eval('%s / %s' % (left, points)) + if left < 0: + #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 ) + 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 ) + 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 ) + 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 ) + else: + txt = '%s uses %s ( level %s, "%s" )' % ( charNameL, name, level, descr ) #m 1.5002 + self.chat.ParsePost( txt, True, False ) + s = '' + if left != 1: + s = 's' + #numcast is meaningless here -mgt + #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 ) + self.root.pp.set_char_pp('current1',left) #a 1.5002 + + def refresh_powers(self): + self.powers = {} + + tree = self.tree + icons = self.tree.icons + tree.CollapseAndReset(self.mytree_node) + node_list = self.master_dom.getElementsByTagName('power') + for n in node_list: + name = n.getAttribute('name') + new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear']) + tree.SetPyData(new_tree_node,self) + self.powers[name]=n + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,power_panel,"Powers") + wnd.title = "Powers" + return wnd + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Powers</th></tr><tr><td><br>" + n_list = self.master_dom._get_childNodes() + for n in n_list: + html_str += "(" + n.getAttribute('level') + ") " + n.getAttribute('name')+ ", " + html_str = html_str[:len(html_str)-2] + "</td></tr></table>" + return html_str + + +class power_panel(wx.Panel): + def __init__(self, parent, handler): + #m 1.5015 corrected typo, was Pionic. + pname = handler.master_dom.setAttribute("name", 'Psionic Powers') + self.hparent = handler #a 1.5002 allow ability to run up tree. In this + #a 1.5002 case, we need the functional parent, not the invoking parent. + self.root = getRoot(self) #a (debug) 1.5002,1.5014 + + wx.Panel.__init__(self, parent, -1) + self.grid = wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) + self.handler = handler + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.grid, 1, wx.EXPAND) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(wx.Button(self, 10, "Remove Power"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 20, "Add Power"), 1, wx.EXPAND) + sizer1.Add(wx.Size(10,10)) + sizer1.Add(wx.Button(self, 30, "Refresh Power"), 1, wx.EXPAND) + + sizer.Add(sizer1, 0, wx.EXPAND) + self.sizer = sizer + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + #self.Bind(wx.EVT_SIZE, self.on_size) + + 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_powers, id=30) + self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) + n_list = handler.master_dom._get_childNodes() + self.n_list = n_list + self.master_dom = handler.master_dom + self.grid.CreateGrid(len(n_list),5,1) + self.grid.SetRowLabelSize(0) + self.grid.SetColLabelValue(0,"PP") + self.grid.SetColLabelValue(1,"Lvl") + self.grid.SetColLabelValue(2,"Power") + self.grid.SetColLabelValue(3,"Desc") + self.grid.SetColLabelValue(4,"Type") + for i in range(len(n_list)): + self.refresh_row(i) + self.refresh_data() + self.temp_dom = None + + def on_cell_change(self,evt): + row = evt.GetRow() + col = evt.GetCol() + value = self.grid.GetCellValue(row,col) + """if col == 0: + self.n_list[row].setAttribute('memrz',value)""" + + + def refresh_row(self,i): + power = self.n_list[i] + + point = power.getAttribute('point') + name = power.getAttribute('name') + type = power.getAttribute('desc') + test = power.getAttribute('test') + level = power.getAttribute('level') + self.grid.SetCellValue(i,0,point) + self.grid.SetReadOnly(i,0) + self.grid.SetCellValue(i,1,level) + self.grid.SetReadOnly(i,1) + 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,4,test) + self.grid.SetReadOnly(i,4) + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + + def on_add(self,evt): + if not self.temp_dom: + tmp = open(orpg.dirpath.dir_struct["dnd3e"]+"dnd3epowers.xml","r") + + xml_dom = parseXml_with_dlg(self,tmp.read()) + xml_dom = xml_dom._get_firstChild() + tmp.close() + self.temp_dom = xml_dom + f_list = self.temp_dom.getElementsByTagName('power') + opts = [] + #lvl = int(dnd3e_char_child.get_char_lvl('level')) + #castlvl = lvl / 2 + for f in f_list: + spelllvl = f.getAttribute('level') + #if spelllvl <= "1": + # opts.append("(" + f.getAttribute('level') + ") - " + f.getAttribute('name') + " - " + f.getAttribute('test')) + #else: + # if eval('%d >= %s' %(castlvl, spelllvl)): + opts.append("(" + f.getAttribute('level') + ") - " + + f.getAttribute('name') + " - " + f.getAttribute('test')) + dlg = wx.SingleChoiceDialog(self,'Choose Power','Powers',opts) + if dlg.ShowModal() == wx.ID_OK: + i = dlg.GetSelection() + new_node = self.master_dom.appendChild(f_list[i].cloneNode(False)) + self.grid.AppendRows(1) + self.n_list = self.master_dom.getElementsByTagName('power') + self.refresh_row(self.grid.GetNumberRows()-1) + self.handler.refresh_powers() + dlg.Destroy() + + def on_remove(self,evt): + rows = self.grid.GetNumberRows() + for i in range(rows): + if self.grid.IsInSelection(i,0): + self.grid.DeleteRows(i) + self.master_dom.removeChild(self.n_list[i]) + self.n_list = self.master_dom.getElementsByTagName('weapon') + self.handler.refresh_powers() + + def on_refresh_powers( self, evt ): + #a 1.5002,1.5014 s + self.root.pp.set_char_pp('current1',self.root.pp.get_char_pp('max1')) + self.root.pp.set_char_pp('free',self.root.pp.get_char_pp('maxfree')) + #a 1.5002,1.5014 e + + + + def on_size(self,event): + s = self.GetClientSizeTuple() + self.grid.SetDimensions(0,0,s[0],s[1]-25) + self.sizer.SetDimension(0,s[1]-25,s[0],25) + (w,h) = self.grid.GetClientSizeTuple() + cols = self.grid.GetNumberCols() + col_w = w/(cols) + for i in range(0,cols): + self.grid.SetColSize(i,col_w) + self.grid.SetColSize(0,w * 0.05) + self.grid.SetColSize(1,w * 0.05) + self.grid.SetColSize(2,w * 0.30) + self.grid.SetColSize(3,w * 0.30) + self.grid.SetColSize(4,w * 0.30) + + def refresh_data(self): + + for i in range(len(self.n_list)): + self.refresh_row(i) + +class dnd3epp(snp_char_child): + """ Node Handler for power points. This handler will be + created by dnd3echar_handler. + """ + def __init__(self,xml_dom,tree_node,parent): + snp_char_child.__init__(self,xml_dom,tree_node,parent) + self.hparent = parent #a 1.5002 allow ability to run up tree. + self.root = getRoot(self) + self.root.pp = self + self.ppPanel=None + + + def get_design_panel(self,parent): + wnd = outline_panel(parent,self,pp_panel,"Power Points") + wnd.title = "Power Points" + return wnd + + + def tohtml(self): + html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 >" + #html_str += "<th colspan=8>Power Points</th></tr>" #d 1.6010 + html_str += "<th colspan=7>Power Points</th>" #a 1.6010 + #m 1.6010 rearanged everything below to "return html_str" + html_str += "</tr><tr>" + html_str += "<th colspan=2>Max:</th>" + html_str += "<td>"+self.master_dom.getAttribute('max1')+"</td>" + html_str += "<th colspan=3>Max Talents/day:</th>" + html_str += "<td>"+self.master_dom.getAttribute('maxfree')+"</td>" + html_str += "</tr><tr>" + html_str += "<th colspan=2>Current:</th>" + html_str += "<td>"+self.master_dom.getAttribute('current1')+"</td>" + html_str += "<th colspan=3>Current Talents/day:</th>" + html_str += "<td>"+self.master_dom.getAttribute('free')+"</td>" + html_str += "</tr></table>" + return html_str + + def get_char_pp( self, attr ): + pp = self.master_dom.getAttribute(attr) + #print "dnd3epp -get_char_pp: attr,pp",attr,pp + return pp + + def set_char_pp( self, attr, evl ): + qSub = str(evl) #a 1.5014 must force it to be a string for next call. + self.master_dom.setAttribute(attr, qSub) + #This function needs to be looked at the idea is to refresh the power panel + #But it causes a seg fault when you refresh from powers -mgt + #if self.ppPanel: #a 1.5015 + # self.ppPanel.on_refresh(attr,qSub) #a 1.5015 + + +class pp_panel(wx.Panel): + def __init__(self, parent, handler): + wx.Panel.__init__(self, parent, -1) + self.hparent = handler #a 1.5002 allow ability to run up tree. + #a 1.5002 we need the functional parent, not the invoking parent. + self.hparent.ppPanel=self #a 1.5xx + + pname = handler.master_dom.setAttribute("name", 'PowerPoints') + self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap + self.master_dom = handler.master_dom + + self.static1= wx.StaticText(self, -1, "PP Current:") #a 1.5015 + self.dyn1= wx.TextCtrl(self, PP_CUR, + self.master_dom.getAttribute('current1')) #a 1.5015 + self.dyn3= wx.TextCtrl(self, PP_FRE, + self.master_dom.getAttribute('free')) #a 1.5015 +# self.sizer.AddMany([ (wx.StaticText(self, -1, "PP Current:"), #d 1.5015 +# 0, wx.ALIGN_CENTER_VERTICAL), +# (wx.TextCtrl(self, PP_CUR, #d 1.5015 +# self.master_dom.getAttribute('current1')), 0, wx.EXPAND), + self.sizer.AddMany([ (self.static1, 0, wx.ALIGN_CENTER_VERTICAL), + (self.dyn1, 0, wx.EXPAND), + (wx.StaticText(self, -1, "PP Max:"), 0, wx.ALIGN_CENTER_VERTICAL), + (wx.TextCtrl(self, PP_MAX, + self.master_dom.getAttribute('max1')), 0, wx.EXPAND), + (wx.StaticText(self, -1, "Current Free Talants per day:"), + 0, wx.ALIGN_CENTER_VERTICAL), + (self.dyn3, 0, wx.EXPAND), #a 1.5015 +# (wx.TextCtrl(self, PP_FRE, +# self.master_dom.getAttribute('free')), 0, wx.EXPAND),#d 1.5015 + (wx.StaticText(self, -1, "Max Free Talants per day:"), + 0, wx.ALIGN_CENTER_VERTICAL), + (wx.TextCtrl(self, PP_MFRE, + self.master_dom.getAttribute('maxfree')), 0, wx.EXPAND), + ]) + + self.sizer.AddGrowableCol(1) + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Fit() + + #self.Bind(wx.EVT_SIZE, self.on_size) + self.Bind(wx.EVT_TEXT, self.on_text, id=PP_MAX) + self.Bind(wx.EVT_TEXT, self.on_text, id=PP_CUR) + self.Bind(wx.EVT_TEXT, self.on_text, id=PP_FRE) + self.Bind(wx.EVT_TEXT, self.on_text, id=PP_MFRE) + + def on_text(self,evt): + id = evt.GetId() + if id == PP_CUR: + self.master_dom.setAttribute('current1',evt.GetString()) + elif id == PP_MAX: + self.master_dom.setAttribute('max1',evt.GetString()) + elif id == PP_FRE: + self.master_dom.setAttribute('free',evt.GetString()) + elif id == PP_MFRE: + self.master_dom.setAttribute('maxfree',evt.GetString()) + + def on_size(self,evt): + s = self.GetClientSizeTuple() + self.sizer.SetDimension(0,0,s[0],s[1]) + + #a 5.015 this whole function. + def on_refresh(self,attr,value): + if attr == 'current1': + self.dyn1.SetValue(value) + else: + self.dyn3.SetValue(value)