156
|
1 # Copyright (C) 2000-2001 The OpenRPG Project
|
|
2 #
|
|
3 # openrpg-dev@lists.sourceforge.net
|
|
4 #
|
|
5 # This program is free software; you can redistribute it and/or modify
|
|
6 # it under the terms of the GNU General Public License as published by
|
|
7 # the Free Software Foundation; either version 2 of the License, or
|
|
8 # (at your option) any later version.
|
|
9 #
|
|
10 # This program is distributed in the hope that it will be useful,
|
|
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 # GNU General Public License for more details.
|
|
14 #
|
|
15 # You should have received a copy of the GNU General Public License
|
|
16 # along with this program; if not, write to the Free Software
|
|
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
18 # --
|
|
19 #
|
|
20 # File: d20.py
|
|
21 # Author: Chris Davis
|
|
22 # Maintainer:
|
|
23 # Version:
|
184
|
24 # $Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
|
156
|
25 #
|
|
26 # Description: The file contains code for the d20 nodehanlers
|
|
27 #
|
|
28
|
184
|
29 __version__ = "$Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
|
156
|
30
|
152
|
31 from core import *
|
156
|
32 from containers import *
|
|
33 import re
|
|
34 from xml.etree.ElementTree import ElementTree, Element, iselement
|
135
|
35 from xml.etree.ElementTree import fromstring, tostring, parse, XML
|
156
|
36 from orpg.tools.orpg_log import debug
|
193
|
37 from orpg.tools.InterParse import Parse
|
156
|
38
|
|
39 D20_EXPORT = wx.NewId()
|
|
40 ############################
|
|
41 ## d20 character node handler
|
|
42 ############################
|
|
43 ## Spells code - added by Dragonstar
|
|
44 ##Powers, Divine spells, inventory, howto, power points by Digitalxero
|
|
45 ##The whole look and easy of use redone by Digitalxero
|
|
46 class container_handler(node_handler):
|
|
47 """ should not be used! only a base class!
|
|
48 <nodehandler name='?' module='core' class='container_handler' />
|
|
49 """
|
|
50 def __init__(self,xml,tree_node):
|
|
51 node_handler.__init__(self,xml,tree_node)
|
|
52 self.load_children()
|
|
53
|
|
54 def load_children(self):
|
|
55 children = self.xml.getchildren()
|
|
56 for c in children:
|
|
57 self.tree.load_xml(c,self.mytree_node)
|
|
58
|
|
59 def on_drop(self,evt):
|
|
60 drag_obj = self.tree.drag_obj
|
|
61 if drag_obj == self: return
|
|
62 opt = wx.MessageBox("Add node as child?","Container Node",wx.YES_NO|wx.CANCEL)
|
|
63 if opt == wx.YES:
|
|
64 xml = self.tree.drag_obj.delete()
|
|
65 xml = self.xml.append(xml,None)
|
|
66 self.tree.load_xml(xml, self.mytree_node)
|
|
67 self.tree.Expand(self.mytree_node)
|
|
68 elif opt == wx.NO: node_handler.on_drop(self,evt)
|
|
69
|
|
70 def tohtml(self):
|
|
71 cookie = 0
|
|
72 html_str = "<table border=\"1\" ><tr><td>"
|
|
73 html_str += "<b>"+self.xml.get("name") + "</b>"
|
|
74 html_str += "</td></tr>\n"
|
|
75 html_str += "<tr><td>"
|
|
76 max = tree.GetChildrenCount(handler.mytree_node,0)
|
152
|
77 try: (child,cookie)=self.tree.GetFirstChild(self.mytree_node,cookie)
|
156
|
78 # If this happens we probably have a newer version of wxPython
|
|
79 except: (child,cookie)=self.tree.GetFirstChild(self.mytree_node)
|
|
80 obj = self.tree.GetPyData(child)
|
|
81 for m in range(max):
|
|
82 html_str += "<p>" + obj.tohtml()
|
|
83 if m < max-1:
|
|
84 child = self.tree.GetNextSibling(child)
|
|
85 if child.IsOk(): obj = self.tree.GetPyData(child)
|
|
86 html_str += "</td></tr></table>"
|
|
87 return html_str
|
|
88
|
|
89 def get_size_constraint(self):
|
|
90 return 1
|
|
91
|
|
92 def get_char_name( self ):
|
|
93 return self.child_handlers['general'].get_char_name()
|
|
94
|
|
95 def set_char_pp(self,attr,evl):
|
|
96 return self.child_handlers['pp'].set_char_pp(attr,evl)
|
|
97
|
|
98 def get_char_pp( self, attr ):
|
|
99 return self.child_handlers['pp'].get_char_pp(attr)
|
|
100
|
|
101 def get_char_lvl( self, attr ):
|
|
102 return self.child_handlers['classes'].get_char_lvl(attr)
|
|
103
|
|
104
|
|
105 class d20char_handler(node_handler):
|
|
106 """ Node handler for a d20 charactor
|
|
107 <nodehandler name='?' module='d20' class='d20char_handler2' />
|
|
108 """
|
|
109 def __init__(self,xml,tree_node):
|
|
110 node_handler.__init__(self,xml,tree_node)
|
|
111 self.frame = component.get('frame')
|
|
112 self.child_handlers = {}
|
|
113 self.new_child_handler('howtouse','HowTO use this tool',d20howto,'note')
|
|
114 self.new_child_handler('general','General Information',d20general,'gear')
|
|
115 self.new_child_handler('inventory','Money and Inventory',d20inventory,'money')
|
|
116 self.new_child_handler('abilities','Abilities Scores',d20ability,'gear')
|
|
117 self.new_child_handler('classes','Classes',d20classes,'knight')
|
|
118 self.new_child_handler('saves','Saves',d20saves,'skull')
|
|
119 self.new_child_handler('skills','Skills',d20skill,'book')
|
|
120 self.new_child_handler('feats','Feats',d20feats,'book')
|
|
121 self.new_child_handler('spells','Spells',d20spells,'book')
|
|
122 self.new_child_handler('divine','Divine Spells',d20divine,'book')
|
|
123 self.new_child_handler('powers','Powers',d20powers,'questionhead')
|
|
124 self.new_child_handler('hp','Hit Points',d20hp,'gear')
|
|
125 self.new_child_handler('pp','Power Points',d20pp,'gear')
|
|
126 self.new_child_handler('attacks','Attacks',d20attacks,'spears')
|
|
127 self.new_child_handler('ac','Armor',d20armor,'spears')
|
|
128 self.myeditor = None
|
|
129
|
|
130 def on_version(self,old_version):
|
|
131 node_handler.on_version(self,old_version)
|
|
132 if old_version == "":
|
|
133 data = parse(orpg.dirpath.dir_struct["nodes"]+"d20character.xml").getroot()
|
|
134 for tag in ("howtouse","inventory","powers","divine","pp"):
|
|
135 self.xml.append(data.find(tag))
|
|
136
|
|
137 ## add new atts
|
|
138 melee_attack = self.xml.find('melee')
|
|
139 melee_attack.set("second","0")
|
|
140 melee_attack.set("third","0")
|
|
141 melee_attack.set("forth","0")
|
|
142 melee_attack.set("fifth","0")
|
|
143 melee_attack.set("sixth","0")
|
|
144 range_attack = self.xml.find('ranged')
|
|
145 range_attack.set("second","0")
|
|
146 range_attack.set("third","0")
|
|
147 range_attack.set("forth","0")
|
|
148 range_attack.set("fifth","0")
|
|
149 range_attack.set("sixth","0")
|
|
150
|
|
151 gen_list = self.xml.find('general')
|
|
152
|
152
|
153 for tag in ("currentxp","xptolevel"): gen_list.append(data.find(tag))
|
156
|
154 print old_version
|
|
155
|
|
156
|
|
157 def get_char_name( self ):
|
|
158 return self.child_handlers['general'].get_char_name()
|
|
159
|
|
160 def set_char_pp(self,attr,evl):
|
|
161 return self.child_handlers['pp'].set_char_pp(attr,evl)
|
|
162
|
|
163 def get_char_pp( self, attr ):
|
|
164 return self.child_handlers['pp'].get_char_pp(attr)
|
|
165
|
|
166 def get_char_lvl( self, attr ):
|
|
167 return self.child_handlers['classes'].get_char_lvl(attr)
|
|
168
|
|
169 def new_child_handler(self,tag,text,handler_class,icon='gear'):
|
|
170 tree = self.tree
|
|
171 i = self.tree.icons[icon]
|
|
172 new_tree_node = tree.AppendItem(self.mytree_node,text,i,i)
|
|
173 handler = handler_class(self.xml.find(tag),new_tree_node,self)
|
|
174 tree.SetPyData(new_tree_node,handler)
|
|
175 self.child_handlers[tag] = handler
|
|
176
|
|
177 def get_design_panel(self,parent):
|
|
178 return tabbed_panel(parent,self,1)
|
|
179
|
|
180 def get_use_panel(self,parent):
|
|
181 return tabbed_panel(parent,self,2)
|
|
182
|
|
183 def tohtml(self):
|
|
184 html_str = "<table><tr><td colspan=2 >"+self.child_handlers['general'].tohtml()+"</td></tr>"
|
|
185 html_str += "<tr><td width='50%' valign=top >"+self.child_handlers['abilities'].tohtml()
|
|
186 html_str += "<P>" + self.child_handlers['saves'].tohtml()
|
|
187 html_str += "<P>" + self.child_handlers['attacks'].tohtml()
|
|
188 html_str += "<P>" + self.child_handlers['ac'].tohtml()
|
|
189 html_str += "<P>" + self.child_handlers['feats'].tohtml()
|
|
190 html_str += "<P>" + self.child_handlers['spells'].tohtml()
|
|
191 html_str += "<P>" + self.child_handlers['divine'].tohtml()
|
|
192 html_str += "<P>" + self.child_handlers['powers'].tohtml()
|
|
193 html_str += "<P>" + self.child_handlers['inventory'].tohtml() +"</td>"
|
|
194 html_str += "<td width='50%' valign=top >"+self.child_handlers['classes'].tohtml()
|
|
195 html_str += "<P>" + self.child_handlers['hp'].tohtml()
|
|
196 html_str += "<P>" + self.child_handlers['pp'].tohtml()
|
|
197 html_str += "<P>" + self.child_handlers['skills'].tohtml() +"</td>"
|
|
198 html_str += "</tr></table>"
|
|
199 return html_str
|
|
200
|
|
201 def about(self):
|
|
202 """html_str = "<img src='" + orpg.dirpath.dir_struct["icon"]+'d20_logo.gif' "><br /><b>d20 Character Tool v0.7 beta</b>"
|
|
203 html_str += "<br />by Chris Davis<br />chris@rpgarchive.com"
|
152
|
204 return html_str"""
|
|
205 text = 'd20 Character Tool 0.7 beta\n'
|
|
206 text += 'by Chris Davis chris@rpgarchive.com'
|
156
|
207 return text
|
|
208
|
|
209 def get_char_name( self ):
|
|
210 return self.child_handlers['general'].get_char_name()
|
|
211 def get_armor_class( self ):
|
|
212 return self.child_handlers['ac'].get_armor_class()
|
|
213 def get_max_hp( self ):
|
|
214 return self.child_handlers['hp'].get_max_hp()
|
|
215 def get_current_hp( self ):
|
|
216 return self.child_handlers['hp'].get_current_hp()
|
|
217
|
|
218 def set_char_pp(self,attr,evl):
|
|
219 return self.child_handlers['pp'].set_char_pp(attr,evl)
|
|
220
|
|
221 def get_char_pp( self, attr ):
|
|
222 return self.child_handlers['pp'].get_char_pp(attr)
|
|
223
|
|
224 def get_char_lvl( self, attr ):
|
|
225 return self.child_handlers['classes'].get_char_lvl(attr)
|
|
226
|
152
|
227 """ Removed to use the supplied Tabbed Panel
|
156
|
228 class tabbed_panel(wx.Notebook):
|
|
229 def __init__(self, parent, handler, mode):
|
|
230 wx.Notebook.__init__(self, parent, -1, size=(1200,800))
|
|
231 self.handler = handler
|
|
232 self.parent = parent
|
|
233 tree = self.handler.tree
|
|
234 max = tree.GetChildrenCount(handler.mytree_node)
|
|
235 cookie = 0
|
|
236
|
152
|
237 try: (child,cookie)=tree.GetFirstChild(handler.mytree_node,cookie)
|
156
|
238 # If this happens we probably have a newer version of wxPython
|
|
239 except: (child,cookie)=tree.GetFirstChild(handler.mytree_node)
|
|
240 if not child.IsOk(): return
|
|
241 obj = tree.GetPyData(child)
|
|
242 for m in range(max):
|
|
243 if mode == 1: panel = obj.get_design_panel(self)
|
|
244 else: panel = obj.get_use_panel(self)
|
|
245 name = obj.xml.get("name")
|
|
246 if panel: self.AddPage(panel,name)
|
|
247 if m < max-1:
|
|
248 child = tree.GetNextSibling(child)
|
|
249 if child.IsOk(): obj = tree.GetPyData(child)
|
|
250 else: break
|
|
251
|
|
252 def about(self):
|
|
253 html_str = "<img src='" + orpg.dirpath.dir_struct["icon"]+'d20_logo.gif' "><br /><b>d20 Character Tool v0.7 beta</b>"
|
|
254 html_str += "<br />by Chris Davis<br />chris@rpgarchive.com"
|
|
255 return html_str
|
|
256
|
|
257 def get_char_name( self ):
|
|
258 return self.child_handlers['general'].get_char_name()
|
|
259
|
|
260 def set_char_pp(self,attr,evl):
|
|
261 return self.child_handlers['pp'].set_char_pp(attr,evl)
|
|
262
|
|
263 def get_char_pp( self, attr ):
|
|
264 return self.child_handlers['pp'].get_char_pp(attr)
|
|
265
|
|
266 def get_char_lvl( self, attr ):
|
|
267 return self.child_handlers['classes'].get_char_lvl(attr)
|
|
268 """
|
|
269 class d20_char_child(node_handler):
|
|
270 """ Node Handler for skill. This handler will be
|
|
271 created by d20char_handler.
|
|
272 """
|
|
273 def __init__(self,xml,tree_node,parent):
|
|
274 node_handler.__init__(self,xml,tree_node)
|
|
275 self.char_hander = parent
|
|
276 self.drag = False
|
|
277 self.frame = component.get('frame')
|
|
278 self.myeditor = None
|
|
279
|
|
280 def on_drop(self,evt):
|
|
281 pass
|
|
282
|
|
283 def on_rclick(self,evt):
|
|
284 pass
|
|
285
|
|
286 def on_ldclick(self,evt):
|
|
287 return
|
|
288 if self.myeditor == None or self.myeditor.destroyed:
|
|
289 title = self.xml.get('name') + " Editor"
|
|
290 self.myeditor = wx.Frame(self.frame, -1, title)
|
|
291 if wx.Platform == '__WXMSW__':
|
|
292 icon = wx.Icon(orpg.dirpath.dir_struct["icon"]+'grid.ico', wx.BITMAP_TYPE_ICO)
|
|
293 self.myeditor.SetIcon(icon)
|
|
294 del icon
|
|
295 wnd = self.get_design_panel(self.myeditor)
|
|
296 self.myeditor.panel = wnd
|
|
297 self.wnd = wnd
|
|
298 self.myeditor.Show(1)
|
|
299 else:
|
|
300 self.myeditor.Raise()
|
|
301
|
|
302 def on_html(self,evt):
|
|
303 html_str = self.tohtml()
|
|
304 wnd = http_html_window(self.frame.note,-1)
|
|
305 wnd.title = self.xml.get('name')
|
|
306 self.frame.add_panel(wnd)
|
|
307 wnd.SetPage(html_str)
|
|
308
|
|
309 def get_design_panel(self,parent):
|
|
310 pass
|
|
311
|
|
312 def get_use_panel(self,parent):
|
|
313 return self.get_design_panel(parent)
|
|
314
|
|
315 def delete(self):
|
|
316 pass
|
|
317
|
|
318
|
|
319 class d20skill(d20_char_child):
|
|
320 """ Node Handler for skill. This handler will be
|
|
321 created by d20char_handler.
|
|
322 """
|
|
323 def __init__(self,xml,tree_node,parent):
|
|
324 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
325 tree = self.tree
|
|
326 icons = self.tree.icons
|
|
327 self.skills={}
|
|
328 for n in self.xml.findall('skill'):
|
|
329 name = n.get('name')
|
|
330 self.skills[name] = n
|
|
331 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear'])
|
|
332 tree.SetPyData(new_tree_node,self)
|
|
333
|
|
334 def get_mod(self,name):
|
|
335 skill = self.skills[name]
|
|
336 stat = skill.get('stat')
|
|
337 ac = int(skill.get('armorcheck'))
|
|
338 if ac:
|
|
339 ac = self.char_hander.child_handlers['ac'].get_check_pen()
|
|
340 stat_mod = self.char_hander.child_handlers['abilities'].get_mod(stat)
|
|
341 rank = int(skill.get('rank'))
|
|
342 misc = int(skill.get('misc'))
|
|
343 total = stat_mod + rank + misc + ac
|
|
344 return total
|
|
345
|
|
346 def on_rclick(self,evt):
|
|
347 item = self.tree.GetSelection()
|
|
348 name = self.tree.GetItemText(item)
|
|
349 if item == self.mytree_node: d20_char_child.on_ldclick(self,evt)
|
|
350 else:
|
|
351 skill = self.skills[name];
|
|
352 untrained = skill.get('untrained');
|
|
353 rank = skill.get('rank');
|
|
354 if untrained == "0" and rank == "0": txt = '%s Skill Check: Untrained' % (name)
|
|
355 else:
|
|
356 mod = self.get_mod(name)
|
|
357 if mod >= 0: mod1 = "+"
|
|
358 else: mod1 = ""
|
|
359 txt = '%s Skill Check: [1d20%s%s]' % (name, mod1, mod)
|
|
360 chat = self.chat
|
243
|
361 Parse.Post( txt, self.chat, True, True )
|
156
|
362
|
|
363 def get_design_panel(self,parent):
|
|
364 wnd = outline_panel(parent,self,skill_grid,"Skills")
|
|
365 wnd.title = "Skills (edit)"
|
|
366 return wnd
|
|
367
|
|
368 def tohtml(self):
|
|
369 html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 ><th width='30%'>Skill</th><th>Key</th>
|
|
370 <th>Rank</th><th>Abil</th><th>Misc</th><th>Total</th></tr>"""
|
|
371 for n in self.xml.findall('skill'):
|
|
372 name = n.get('name')
|
|
373 stat = n.get('stat')
|
|
374 rank = n.get('rank')
|
|
375 html_str = html_str + "<tr ALIGN='center'><td>"+name+"</td><td>"+stat+"</td><td>"+rank+"</td>"
|
|
376 stat_mod = str(self.char_hander.child_handlers['abilities'].get_mod(stat))
|
|
377 misc = n.get('misc')
|
|
378 mod = str(self.get_mod(name))
|
|
379 if mod >= 0: mod1 = "+"
|
|
380 else: mod1 = ""
|
|
381 html_str = html_str + "<td>"+stat_mod+"</td><td>"+misc+'</td><td>%s%s</td></tr>' % (mod1, mod)
|
|
382 html_str = html_str + "</table>"
|
|
383 return html_str
|
|
384
|
|
385
|
|
386 class d20ability(d20_char_child):
|
|
387 """ Node Handler for ability. This handler will be
|
|
388 created by d20char_handler.
|
|
389 """
|
|
390 def __init__(self,xml,tree_node,parent):
|
|
391 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
392 self.abilities = {}
|
|
393 tree = self.tree
|
|
394 icons = tree.icons
|
|
395 for n in self.xml.findall('stat'):
|
|
396 name = n.get('abbr')
|
|
397 self.abilities[name] = n
|
|
398 new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] )
|
|
399 tree.SetPyData( new_tree_node, self )
|
|
400
|
|
401 def on_rclick( self, evt ):
|
|
402 item = self.tree.GetSelection()
|
|
403 name = self.tree.GetItemText( item )
|
|
404 if item == self.mytree_node:
|
|
405 d20_char_child.on_ldclick( self, evt )
|
|
406 else:
|
|
407 mod = self.get_mod( name )
|
|
408 if mod >= 0: mod1 = "+"
|
|
409 else: mod1 = ""
|
|
410 chat = self.chat
|
|
411 txt = '%s check: [1d20%s%s]' % ( name, mod1, mod )
|
243
|
412 Parse.Post( txt, self.chat, True, True )
|
156
|
413
|
|
414 def get_mod(self,abbr):
|
|
415 score = int(self.abilities[abbr].get('base'))
|
|
416 mod = (score - 10) / 2
|
|
417 return mod
|
|
418
|
|
419 def set_score(self,abbr,score):
|
|
420 if score >= 0:
|
|
421 self.abilities[abbr].set("base",str(score))
|
|
422
|
|
423 def get_design_panel(self,parent):
|
|
424 wnd = outline_panel(parent,self,abil_grid,"Abilities")
|
|
425 wnd.title = "Abilities (edit)"
|
|
426 return wnd
|
|
427
|
|
428 def tohtml(self):
|
|
429 html_str = """<table border='1' width=100%><tr BGCOLOR=#E9E9E9 ><th width='50%'>Ability</th>
|
|
430 <th>Base</th><th>Modifier</th></tr>"""
|
|
431 for n in self.xml.findall('stat'):
|
|
432 name = n.get('name')
|
|
433 abbr = n.get('abbr')
|
|
434 base = n.get('base')
|
|
435 mod = str(self.get_mod(abbr))
|
|
436 if mod >= 0: mod1 = "+"
|
|
437 else: mod1 = ""
|
|
438 html_str = html_str + "<tr ALIGN='center'><td>"+name+"</td><td>"+base+'</td><td>%s%s</td></tr>' % (mod1, mod)
|
|
439 html_str = html_str + "</table>"
|
|
440 return html_str
|
|
441
|
|
442
|
|
443 class d20saves(d20_char_child):
|
|
444 """ Node Handler for saves. This handler will be
|
|
445 created by d20char_handler.
|
|
446 """
|
|
447 def __init__(self,xml,tree_node,parent):
|
|
448 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
449 tree = self.tree
|
|
450 icons = self.tree.icons
|
|
451 self.saves={}
|
|
452 for n in self.xml.findall('save'):
|
|
453 name = n.get('name')
|
|
454 self.saves[name] = n
|
|
455 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear'])
|
|
456 tree.SetPyData(new_tree_node,self)
|
|
457
|
|
458 def get_mod(self,name):
|
|
459 save = self.saves[name]
|
|
460 stat = save.get('stat')
|
|
461 stat_mod = self.char_hander.child_handlers['abilities'].get_mod(stat)
|
|
462 base = int(save.get('base'))
|
|
463 miscmod = int(save.get('miscmod'))
|
|
464 magmod = int(save.get('magmod'))
|
|
465 total = stat_mod + base + miscmod + magmod
|
|
466 return total
|
|
467
|
|
468 def on_rclick(self,evt):
|
|
469 item = self.tree.GetSelection()
|
|
470 name = self.tree.GetItemText(item)
|
|
471 if item == self.mytree_node:
|
|
472 d20_char_child.on_ldclick(self,evt)
|
|
473
|
|
474 else:
|
|
475 mod = self.get_mod(name)
|
|
476 if mod >= 0: mod1 = "+"
|
|
477 else: mod1 = ""
|
|
478 chat = self.chat
|
|
479 txt = '%s save: [1d20%s%s]' % (name, mod1, mod)
|
243
|
480 Parse.Post( txt, self.chat, True, True )
|
156
|
481
|
|
482 def get_design_panel(self,parent):
|
|
483 wnd = outline_panel(parent,self,save_grid,"Saves")
|
|
484 wnd.title = "Saves"
|
|
485 return wnd
|
|
486
|
|
487 def tohtml(self):
|
|
488 html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 ><th width='30%'>Save</th>
|
|
489 <th>Key</th><th>Base</th><th>Abil</th><th>Magic</th>
|
|
490 <th>Misc</th><th>Total</th></tr>"""
|
|
491 for n in self.xml.findall('save'):
|
|
492 name = n.get('name')
|
|
493 stat = n.get('stat')
|
|
494 base = n.get('base')
|
|
495 html_str = html_str + "<tr ALIGN='center'><td>"+name+"</td><td>"+stat+"</td><td>"+base+"</td>"
|
|
496 stat_mod = str(self.char_hander.child_handlers['abilities'].get_mod(stat))
|
|
497 mag = n.get('magmod')
|
|
498 misc = n.get('miscmod')
|
|
499 mod = str(self.get_mod(name))
|
|
500 if mod >= 0: mod1 = "+"
|
|
501 else: mod1 = ""
|
|
502 html_str = html_str + "<td>"+stat_mod+"</td><td>"+mag+"</td>"
|
|
503 html_str = html_str + '<td>'+misc+'</td><td>%s%s</td></tr>' % (mod1, mod)
|
|
504 html_str = html_str + "</table>"
|
|
505 return html_str
|
|
506
|
|
507
|
|
508 class d20general(d20_char_child):
|
|
509 """ Node Handler for general information. This handler will be
|
|
510 created by d20char_handler.
|
|
511 """
|
|
512 def __init__(self,xml,tree_node,parent):
|
|
513 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
514
|
|
515 def get_design_panel(self,parent):
|
|
516 wnd = outline_panel(parent,self,gen_grid,"General Information")
|
|
517 wnd.title = "General Info"
|
|
518 return wnd
|
|
519
|
|
520 def tohtml(self):
|
|
521 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>"
|
|
522 for n in self.xml:
|
|
523 html_str += "<B>"+n.tag.capitalize() +":</B> "
|
|
524 html_str += n.text + ", "
|
|
525 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
526 return html_str
|
|
527
|
|
528 def on_name_change(self,name):
|
|
529 self.char_hander.rename(name)
|
|
530
|
|
531 def get_char_name( self ):
|
|
532 return self.xml.find( 'name' ).text
|
|
533
|
|
534
|
|
535 class d20classes(d20_char_child):
|
|
536 """ Node Handler for classes. This handler will be
|
|
537 created by d20char_handler.
|
|
538 """
|
|
539 def __init__(self,xml,tree_node,parent):
|
|
540 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
541
|
|
542 def get_design_panel(self,parent):
|
|
543 wnd = outline_panel(parent,self,class_panel,"Classes")
|
|
544 wnd.title = "Classes"
|
|
545 return wnd
|
|
546
|
|
547 def tohtml(self):
|
|
548 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Classes</th></tr><tr><td>"
|
|
549 for n in self.xml: html_str += n.get('name') + " ("+n.get('level')+"), "
|
|
550 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
551 return html_str
|
|
552
|
|
553 def get_char_lvl( self, attr ):
|
|
554 for n in self.xml.findall('class'):
|
|
555 lvl = n.get('level')
|
|
556 type = n.get('name')
|
|
557 if attr == "level": return lvl
|
|
558 elif attr == "class": return type
|
|
559
|
|
560
|
|
561 class d20feats(d20_char_child):
|
|
562 """ Node Handler for classes. This handler will be
|
|
563 created by d20char_handler.
|
|
564 """
|
|
565 def __init__(self,xml,tree_node,parent):
|
|
566 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
567
|
|
568 def get_design_panel(self,parent):
|
|
569 wnd = outline_panel(parent,self,feat_panel,"Feats")
|
|
570 wnd.title = "Feats"
|
|
571 return wnd
|
|
572
|
|
573 def tohtml(self):
|
|
574 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Feats</th></tr><tr><td>"
|
|
575 for n in self.xml: html_str += n.get('name')+ ", "
|
|
576 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
577 return html_str
|
|
578
|
|
579
|
|
580 class d20spells(d20_char_child):
|
|
581 """ Node Handler for classes. This handler will be
|
|
582 created by d20char_handler.
|
|
583 """
|
|
584 def __init__(self,xml,tree_node,parent):
|
|
585 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
586 self.spells = {}
|
|
587 tree = self.tree
|
|
588 icons = self.tree.icons
|
|
589 for n in self.xml.findall( 'spell' ):
|
|
590 name = n.get('name')
|
|
591 self.spells[ name ] = n
|
|
592 new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] )
|
|
593 tree.SetPyData( new_tree_node, self )
|
|
594
|
|
595 def on_rclick( self, evt ):
|
|
596 item = self.tree.GetSelection()
|
|
597 name = self.tree.GetItemText( item )
|
|
598 if item == self.mytree_node:
|
|
599 d20_char_child.on_ldclick( self, evt )
|
|
600 else:
|
|
601 level = self.spells[ name ].get( 'level' )
|
|
602 descr = self.spells[ name ].get( 'desc' )
|
|
603 use = self.spells[ name ].get( 'used' )
|
|
604 memrz = self.spells[ name ].get( 'memrz' )
|
|
605 cname = self.char_hander.get_char_name()
|
|
606 use += '+1'
|
|
607 left = eval( '%s - ( %s )' % ( memrz, use ) )
|
|
608 if left < 0:
|
|
609 txt = '%s Tried to cast %s but has used all of them for today, "Please rest so I can cast more."' % ( cname, name )
|
243
|
610 Parse.Post( txt, self.chat, True, False )
|
156
|
611 else:
|
|
612 txt = '%s casts %s ( level %s, "%s" )' % ( cname, name, level, descr )
|
243
|
613 Parse.Post( txt, self.chat, True, False )
|
156
|
614 s = ''
|
|
615 if left != 1: s = 's'
|
|
616 txt = '%s can cast %s %d more time%s' % ( cname, name, left, s )
|
243
|
617 Parse.Post( txt, self.chat, False, False )
|
156
|
618 self.spells[ name ].set( 'used', `eval( use )` )
|
|
619
|
|
620 def refresh_spells(self):
|
|
621 self.spells = {}
|
|
622 tree = self.tree
|
|
623 icons = self.tree.icons
|
|
624 tree.CollapseAndReset(self.mytree_node)
|
|
625 for n in self.xml.findall('spell'):
|
|
626 name = n.get('name')
|
|
627 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear'])
|
|
628 tree.SetPyData(new_tree_node,self)
|
|
629 self.spells[name]=n
|
|
630
|
|
631 def get_design_panel(self,parent):
|
|
632 wnd = outline_panel(parent,self,spell_panel,"Spells")
|
|
633 wnd.title = "Spells"
|
|
634 return wnd
|
|
635
|
|
636 def tohtml(self):
|
|
637 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Arcane Spells</th></tr><tr><td><br />"
|
|
638 for n in self.xml: html_str += "(" + n.get('level') + ") " + n.get('name')+ ", "
|
|
639 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
640 return html_str
|
|
641
|
|
642 def get_char_lvl( self, attr ):
|
|
643 return self.char_hander.get_char_lvl(attr)
|
|
644
|
|
645 class d20divine(d20_char_child):
|
|
646 """ Node Handler for classes. This handler will be
|
|
647 created by d20char_handler.
|
|
648 """
|
|
649 def __init__(self,xml,tree_node,parent):
|
|
650 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
651 self.spells = {}
|
|
652 tree = self.tree
|
|
653 icons = self.tree.icons
|
|
654 for n in self.xml.findall( 'gift' ):
|
|
655 name = n.get('name')
|
|
656 self.spells[ name ] = n
|
|
657 new_tree_node = tree.AppendItem( self.mytree_node, name, icons['flask'], icons['flask'] )
|
|
658 tree.SetPyData( new_tree_node, self )
|
|
659
|
|
660 def on_rclick( self, evt ):
|
|
661 item = self.tree.GetSelection()
|
|
662 name = self.tree.GetItemText( item )
|
|
663 if item == self.mytree_node:
|
|
664 d20_char_child.on_ldclick( self, evt )
|
|
665 else:
|
|
666 level = self.spells[ name ].get( 'level' )
|
|
667 descr = self.spells[ name ].get( 'desc' )
|
|
668 use = self.spells[ name ].get( 'used' )
|
|
669 memrz = self.spells[ name ].get( 'memrz' )
|
|
670 cname = self.char_hander.get_char_name()
|
|
671 use += '+1'
|
|
672 left = eval( '%s - ( %s )' % ( memrz, use ) )
|
|
673 if left < 0:
|
|
674 txt = '%s Tried to cast %s but has used all of them for today, "Please rest so I can cast more."' % ( cname, name )
|
243
|
675 Parse.Post( txt, self.chat, True, False )
|
156
|
676 else:
|
|
677 txt = '%s casts %s ( level %s, "%s" )' % ( cname, name, level, descr )
|
243
|
678 Parse.Post( txt, self.chat, True, False )
|
156
|
679 s = ''
|
|
680 if left != 1: s = 's'
|
|
681 txt = '%s can cast %s %d more time%s' % ( cname, name, left, s )
|
243
|
682 Parse.Post( txt, self.chat, False, False )
|
156
|
683 self.spells[ name ].set( 'used', `eval( use )` )
|
|
684
|
|
685 def refresh_spells(self):
|
|
686 self.spells = {}
|
|
687 tree = self.tree
|
|
688 icons = self.tree.icons
|
|
689 tree.CollapseAndReset(self.mytree_node)
|
|
690 for n in self.xml.findall('gift'):
|
|
691 name = n.get('name')
|
|
692 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['flask'],icons['flask'])
|
|
693 tree.SetPyData(new_tree_node,self)
|
|
694 self.spells[name]=n
|
|
695
|
|
696 def get_design_panel(self,parent):
|
|
697 wnd = outline_panel(parent,self,divine_panel,"Spells")
|
|
698 wnd.title = "Spells"
|
|
699 return wnd
|
|
700
|
|
701 def tohtml(self):
|
|
702 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Divine Spells</th></tr><tr><td><br />"
|
|
703 for n in self.xml: html_str += "(" + n.get('level') + ") " + n.get('name')+ ", "
|
|
704 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
705 return html_str
|
|
706
|
|
707 def get_char_lvl( self, attr ):
|
|
708 return self.char_hander.get_char_lvl(attr)
|
|
709
|
|
710 class d20powers(d20_char_child):
|
|
711 """ Node Handler for classes. This handler will be
|
|
712 created by d20char_handler.
|
|
713 """
|
|
714 def __init__(self,xml,tree_node,parent):
|
|
715 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
716 #cpp = self.xml.findall( 'pp' ).get('current1')
|
|
717 self.powers = {}
|
|
718 tree = self.tree
|
|
719 icons = self.tree.icons
|
|
720 for n in self.xml.findall( 'power' ):
|
|
721 name = n.get('name')
|
|
722 self.powers[ name ] = n
|
|
723 new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] )
|
|
724 tree.SetPyData( new_tree_node, self )
|
|
725
|
|
726 def on_rclick( self, evt ):
|
|
727 item = self.tree.GetSelection()
|
|
728 name = self.tree.GetItemText( item )
|
|
729 if item == self.mytree_node:
|
|
730 d20_char_child.on_ldclick( self, evt )
|
|
731 else:
|
|
732 level = self.powers[ name ].get( 'level' )
|
|
733 descr = self.powers[ name ].get( 'desc' )
|
|
734 use = self.powers[ name ].get( 'used' )
|
|
735 points = self.powers[ name ].get( 'point' )
|
|
736 cpp = self.char_hander.get_char_pp('current1')
|
|
737 fre = self.char_hander.get_char_pp('free')
|
|
738 cname = self.char_hander.get_char_name()
|
|
739 if level == "0" and fre != "0":
|
|
740 left = eval('%s - ( %s )' % ( fre, points ))
|
|
741 numcast = eval('%s / %s' % (left, points))
|
|
742 if left < 0:
|
|
743 txt = '%s doesnt have enough PowerPoints to use %s' % ( cname, name )
|
243
|
744 Parse.Post( txt, self.chat, True, False )
|
156
|
745 else:
|
|
746 txt = '%s uses %s as a Free Talent ( level %s, "%s" )' % ( cname, name, level, descr )
|
243
|
747 Parse.Post( txt, self.chat, True, False )
|
156
|
748 s = ''
|
|
749 if left != 1: s = 's'
|
|
750 txt = '%s can use %s %d more time%s' % ( cname, name, numcast, s )
|
243
|
751 Parse.Post( txt, self.chat, False, False )
|
156
|
752 self.char_hander.set_char_pp('free', left)
|
|
753 else:
|
|
754 left = eval('%s - ( %s )' % ( cpp, points ))
|
|
755 numcast = eval('%s / %s' % (left, points))
|
|
756 if left < 0:
|
|
757 txt = '%s doesnt have enough PowerPoints to use %s' % ( cname, name )
|
243
|
758 Parse.Post( txt, self.chat, True, False )
|
156
|
759 else:
|
|
760 txt = '%s uses %s ( level %s, "%s" )' % ( cname, name, level, descr )
|
243
|
761 Parse.Post( txt, self.chat, True, False )
|
156
|
762 s = ''
|
|
763 if left != 1: s = 's'
|
|
764 txt = '%s can use %s %d more time%s' % ( cname, name, numcast, s )
|
|
765 txt += ' - And has %d more Powerpoints left' % (left)
|
243
|
766 Parse.Post( txt, self.chat, False, False )
|
156
|
767 self.char_hander.set_char_pp('current1', left)
|
|
768
|
|
769 def refresh_powers(self):
|
|
770 self.powers = {}
|
|
771 tree = self.tree
|
|
772 icons = self.tree.icons
|
|
773 tree.CollapseAndReset(self.mytree_node)
|
|
774 for n in self.xml.findall('power'):
|
|
775 name = n.get('name')
|
|
776 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['questionhead'],icons['questionhead'])
|
|
777 tree.SetPyData(new_tree_node,self)
|
|
778 self.powers[name]=n
|
|
779
|
|
780 def get_design_panel(self,parent):
|
|
781 wnd = outline_panel(parent,self,power_panel,"Powers")
|
|
782 wnd.title = "Powers"
|
|
783 return wnd
|
|
784
|
|
785 def tohtml(self):
|
|
786 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Powers</th></tr><tr><td><br />"
|
|
787 for n in self.xml: html_str += "(" + n.get('level') + ") " + n.get('name')+ ", "
|
|
788 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
789 return html_str
|
|
790
|
|
791 def get_char_lvl( self, attr ):
|
|
792 return self.char_hander.get_char_lvl(attr)
|
|
793
|
|
794 def set_char_pp(self,attr,evl):
|
|
795 return self.char_hander.set_char_pp(attr,evl)
|
|
796
|
|
797 def get_char_pp( self, attr ):
|
|
798 return self.char_hander.get_char_pp(attr)
|
|
799
|
|
800 class d20howto(d20_char_child):
|
|
801 """ Node Handler for hit points. This handler will be
|
|
802 created by d20char_handler.
|
|
803 """
|
|
804 def __init__(self,xml,tree_node,parent):
|
|
805 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
806
|
|
807 def get_design_panel(self,parent):
|
|
808 wnd = outline_panel(parent,self,howto_panel,"How To")
|
|
809 wnd.title = "How To"
|
|
810 return wnd
|
|
811
|
|
812 class d20inventory(d20_char_child):
|
|
813 """ Node Handler for general information. This handler will be
|
|
814 created by d20char_handler.
|
|
815 """
|
|
816 def __init__(self,xml,tree_node,parent):
|
|
817 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
818
|
|
819 def get_design_panel(self,parent):
|
|
820 wnd = outline_panel(parent,self,inventory_grid,"Inventory")
|
|
821 wnd.title = "General Info"
|
|
822 return wnd
|
|
823
|
|
824 def tohtml(self):
|
|
825 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>"
|
|
826 for n in self.xml:
|
|
827 html_str += "<B>"+n.tag.capitalize() +":</B> "
|
|
828 html_str += n.text + "<br />"
|
|
829 html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
|
|
830 return html_str
|
|
831
|
|
832 def on_name_change(self,name):
|
|
833 self.char_hander.rename(name)
|
|
834
|
|
835 def get_char_name( self ):
|
|
836 return self.xml.find( 'name' ).text
|
|
837
|
|
838
|
|
839 class d20hp(d20_char_child):
|
|
840 """ Node Handler for hit points. This handler will be
|
|
841 created by d20char_handler.
|
|
842 """
|
|
843 def __init__(self,xml,tree_node,parent):
|
|
844 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
845
|
|
846 def get_design_panel(self,parent):
|
|
847 wnd = outline_panel(parent,self,hp_panel,"Hit Points")
|
|
848 wnd.title = "Hit Points"
|
|
849 return wnd
|
|
850
|
|
851 def tohtml(self):
|
|
852 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th colspan=4>Hit Points</th></tr>"
|
|
853 html_str += "<tr><th>Max:</th><td>"+self.xml.get('max')+"</td>"
|
|
854 html_str += "<th>Current:</th><td>"+self.xml.get('current')+"</td>"
|
|
855 html_str += "</tr></table>"
|
|
856 return html_str
|
|
857
|
|
858 def get_max_hp( self ):
|
|
859 try: return eval( self.xml.get( 'max' ) )
|
|
860 except: return 0
|
|
861 def get_current_hp( self ):
|
|
862 try: return eval( self.xml.get( 'current' ) )
|
|
863 except: return 0
|
|
864
|
|
865 class d20pp(d20_char_child):
|
|
866 """ Node Handler for power points. This handler will be
|
|
867 created by d20char_handler.
|
|
868 """
|
|
869 def __init__(self,xml,tree_node,parent):
|
|
870 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
871
|
|
872 def get_design_panel(self,parent):
|
|
873 wnd = outline_panel(parent,self,pp_panel,"Power Points")
|
|
874 wnd.title = "Power Points"
|
|
875 return wnd
|
|
876
|
|
877 def tohtml(self):
|
|
878 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th colspan=8>Power Points</th></tr>"
|
|
879 html_str += "<tr><th>Max:</th><td>"+self.xml.get('max1')+"</td>"
|
|
880 html_str += "<th>Current:</th><td>"+self.xml.get('current1')+"</td>"
|
|
881 html_str += "<th>Current Talents/day:</th><td>"+self.xml.get('free')+"</td>"
|
|
882 html_str += "<th>Max Talents/day:</th><td>"+self.xml.get('maxfree')+"</td>"
|
|
883 html_str += "</tr></table>"
|
|
884 return html_str
|
|
885
|
|
886 def get_char_pp( self, attr ):
|
|
887 pp = self.xml.get(attr)
|
|
888 return pp
|
|
889
|
|
890 def set_char_pp( self, attr, evl ):
|
|
891 pp = self.xml.set(attr, evl)
|
|
892 return pp
|
|
893
|
|
894 class d20attacks(d20_char_child):
|
|
895 """ Node Handler for attacks. This handler will be
|
|
896 created by d20char_handler.
|
|
897 """
|
|
898 def __init__(self,xml,tree_node,parent):
|
|
899 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
900 node_list = self.xml.findall('melee')
|
|
901 self.melee = node_list[0]
|
|
902 node_list = self.xml.findall('ranged')
|
|
903 self.ranged = node_list[0]
|
|
904 self.refresh_weapons()
|
|
905
|
|
906 def refresh_weapons(self):
|
|
907 self.weapons = {}
|
|
908 tree = self.tree
|
|
909 icons = self.tree.icons
|
|
910 tree.CollapseAndReset(self.mytree_node)
|
|
911 node_list = self.xml.findall('weapon')
|
|
912 for n in node_list:
|
|
913 name = n.get('name')
|
|
914 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['sword'],icons['sword'])
|
|
915 tree.SetPyData(new_tree_node,self)
|
|
916 self.weapons[name]=n
|
|
917
|
|
918 def get_attack_data(self):
|
|
919 temp = self.melee
|
|
920 base = int(temp.get('base'))
|
|
921 base2 = int(temp.get('second'))
|
|
922 base3 = int(temp.get('third'))
|
|
923 base4 = int(temp.get('forth'))
|
|
924 base5 = int(temp.get('fifth'))
|
|
925 base6 = int(temp.get('sixth'))
|
|
926 misc = int(temp.get('misc'))
|
|
927 return (base, base2, base3, base4, base5, base6, misc)
|
|
928
|
|
929 # Replace any 'S' and 'D' in an attack modifier and damage modifier with the
|
|
930 # strength bonus or dexterity bonus respectively.
|
|
931 def process_mod_codes( self, attack, damage ):
|
|
932 str_mod = self.char_hander.child_handlers['abilities'].get_mod( 'Str' )
|
|
933 dex_mod = self.char_hander.child_handlers['abilities'].get_mod( 'Dex' )
|
|
934 str_re = re.compile('S')
|
|
935 dex_re = re.compile('D')
|
|
936 attack = str_re.sub( str( str_mod ), attack )
|
|
937 attack = dex_re.sub( str( dex_mod ), attack )
|
|
938 damage = str_re.sub( str( str_mod ), damage );
|
|
939 damage = dex_re.sub( str( dex_mod ), damage );
|
|
940 return (attack, damage)
|
|
941
|
|
942 # Decompose a damage string (e.g. longsword +1 sneak attack "1d8+S+1+1d6")
|
|
943 # into it's 4 seperate components <n>d<s>+<mods>+<extra dice>
|
|
944 def decompose_damage( self, damage ):
|
|
945 m = re.match( r"(?P<n>\d+)d(?P<s>\d+)(?P<mods>(\s*(\+|-|/|\*)\s*(\d+|D|S)*)*)(?P<extra>(\s*(\+|-)\s*\d+d\d+)?)\s*$", damage )
|
|
946 return (int(m.group('n')), int(m.group('s')), m.group('mods'), m.group('extra'))
|
|
947
|
|
948 def on_rclick(self,evt):
|
|
949 item = self.tree.GetSelection()
|
|
950 name = self.tree.GetItemText(item)
|
|
951 if item == self.mytree_node:
|
|
952 d20_char_child.on_ldclick(self,evt)
|
|
953 #self.frame.add_panel(self.get_design_panel(self.frame.note))
|
|
954 else:
|
|
955 # Weapon/attack specific attack modifier (e.g. "S+1" for a longsword+1).
|
|
956 attack_mod_str = self.weapons[name].get('mod')
|
|
957
|
|
958 # Weapon/attack specific damage (e.g. "1d8+S+1" for a longsword+1).
|
|
959 damage_str = self.weapons[name].get('damage')
|
|
960 (num_damage_dice, damage_die, damage_mods, extra_damage) = self.decompose_damage( damage_str )
|
|
961
|
|
962 # Replace any 'S' and 'D' in attack_mod_str and damage_str with the
|
|
963 # strength bonus or dexterity bonus respectively.
|
|
964 (attack_mod_str, damage_mods) = self.process_mod_codes( attack_mod_str, damage_mods )
|
|
965
|
|
966 # Base attack bonuses for up to six attacks.
|
|
967 bab_attributes = ['base', 'second', 'third', 'forth', 'fifth', 'sixth']
|
|
968 bab = []
|
|
969 for b in bab_attributes: bab.append( int(self.melee.get( b )) )
|
|
970
|
|
971 # Misc. attack modifier to be applied to *all* attacks.
|
|
972 misc_mod = int(self.melee.get( 'misc' ));
|
|
973
|
|
974 # Attack modifier (except BAB)
|
|
975 attack_mod = misc_mod + eval( attack_mod_str )
|
|
976
|
|
977 # Total damage mod (except extra dice)
|
|
978 if damage_mods != '': damage_mod = eval( damage_mods )
|
|
979 else: damage_mod = 0
|
|
980
|
|
981 # Determine critical hit range and multiplier.
|
|
982 critical_str = self.weapons[name].get( 'critical' )
|
|
983 m = re.match( r"(((?P<min>\d+)-)?\d+/)?x(?P<mult>\d+)", critical_str )
|
|
984 crit_min = m.group( 'min' )
|
|
985 crit_mult = m.group( 'mult' )
|
|
986 if crit_min == None: crit_min = 20
|
|
987 else: crit_min = int( crit_min )
|
|
988 if crit_mult == None: crit_mult = 2
|
|
989 else: crit_mult = int( crit_mult )
|
|
990
|
|
991 # Simple matter to output all the attack/damage lines to the chat buffer.
|
|
992 for i in range( 0, len( bab ) ):
|
|
993 if bab[i] > 0 or i == 0:
|
|
994 attack_roll_str = '[1d20%+d]' % (bab[i] + attack_mod)
|
193
|
995 attack_roll_parsed = Parse.Dice( attack_roll_str )
|
156
|
996 damage_roll_str = '[%dd%d%+d%s]' % (num_damage_dice, damage_die, damage_mod, extra_damage)
|
193
|
997 damage_roll_parsed = Parse.Dice( damage_roll_str )
|
156
|
998 txt = '%s (%s): %s ===> Damage: %s' \
|
|
999 % (name, bab_attributes[i], attack_roll_parsed, damage_roll_parsed)
|
|
1000 self.chat.Post( txt, True, True )
|
|
1001
|
|
1002 # Check for a critical hit
|
|
1003 d20_roll = int(re.match( r".*\[(\d+),.*", attack_roll_parsed ).group(1));
|
|
1004 dmg = damage_str
|
|
1005 if d20_roll >= crit_min:
|
|
1006 for j in range(1,crit_mult): dmg += '+%s' % damage_str
|
|
1007 txt = 'Critical hit? [1d20%+d] ===> Damage: [%dd%d%+d%s]' \
|
|
1008 % (bab[i] + attack_mod, crit_mult*num_damage_dice, \
|
|
1009 damage_die, crit_mult*damage_mod, extra_damage)
|
243
|
1010 Parse.Post( txt, self.chat, True, True )
|
156
|
1011
|
|
1012 def get_design_panel(self,parent):
|
|
1013 wnd = outline_panel(parent,self,attack_panel,"Attacks")
|
|
1014 wnd.title = "Attacks"
|
|
1015 return wnd
|
|
1016
|
|
1017 def get_char_lvl( self, attr ):
|
|
1018 return self.char_hander.get_char_lvl(attr)
|
|
1019
|
|
1020 def tohtml(self):
|
|
1021 babs = self.get_attack_data()
|
|
1022 html_str = "<table width=100% border=1 ><tr ALIGN='center'><th BGCOLOR=#E9E9E9>Base Attack Bonus</th>"
|
|
1023 html_str += '<td>%+d' % babs[0]
|
|
1024 for i in range(1,6):
|
|
1025 if babs[i] > 0: html_str += '/%+d' % babs[i]
|
|
1026 html_str += "</td></tr><tr ALIGN='center' ><th BGCOLOR=#E9E9E9>Misc. Attack Bonus</th>"
|
|
1027 html_str += '<td>%+d</td></tr></table>' % babs[6]
|
|
1028
|
|
1029 n_list = self.xml.findall('weapon')
|
|
1030 for n in n_list:
|
|
1031 (attack_mod, damage_mod) = self.process_mod_codes( n.get( 'mod' ), \
|
|
1032 n.get( 'damage' ) )
|
|
1033 attack_mod = eval( attack_mod )
|
|
1034 html_str += """<P><table width=100% border=1><tr BGCOLOR=#E9E9E9><th colspan=3>Weapon</th>
|
|
1035 <th>Attack</th><th >Damage</th></tr>""" \
|
|
1036 + "<tr ALIGN='center'><td colspan=3>" \
|
|
1037 + n.get('name') + "</td><td>"
|
|
1038 html_str += '%+d</td><td>%s</td></tr>' % (attack_mod, damage_mod)
|
|
1039 html_str += """<tr BGCOLOR=#E9E9E9 ><th>Critical</th><th>Range</th><th>Weight</th>
|
|
1040 <th>Type</th><th>Size</th></tr>""" \
|
|
1041 + "<tr ALIGN='center'><td>" \
|
|
1042 + n.get( 'critical' ) + "</td><td>" \
|
|
1043 + n.get( 'range' ) + "</td><td>" \
|
|
1044 + n.get( 'weight' )+"</td><td>" \
|
|
1045 + n.get( 'type' ) + "</td><td>" \
|
|
1046 + n.get( 'size' ) + "</td></tr></table>"
|
|
1047 return html_str
|
|
1048
|
|
1049 class d20armor(d20_char_child):
|
|
1050 """ Node Handler for ac. This handler will be
|
|
1051 created by d20char_handler.
|
|
1052 """
|
|
1053 def __init__(self,xml,tree_node,parent):
|
|
1054 d20_char_child.__init__(self,xml,tree_node,parent)
|
|
1055
|
|
1056 def get_spell_failure(self):
|
|
1057 return self.get_total('spellfailure')
|
|
1058
|
|
1059 def get_total_weight(self):
|
|
1060 return self.get_total('weight')
|
|
1061
|
|
1062 def get_check_pen(self):
|
|
1063 return self.get_total('checkpenalty')
|
|
1064
|
|
1065 def get_armor_class(self):
|
|
1066 ac_total = 10
|
|
1067 ac_total += self.get_total('bonus')
|
|
1068 dex_mod = self.char_hander.child_handlers['abilities'].get_mod('Dex')
|
|
1069 max_dex = self.get_max_dex()
|
|
1070 if dex_mod < max_dex: ac_total += dex_mod
|
|
1071 else: ac_total += max_dex
|
|
1072 return ac_total
|
|
1073
|
|
1074 def get_max_dex(self):
|
|
1075 armor_list = self.xml.findall('armor')
|
|
1076 dex = 10
|
|
1077 for a in armor_list:
|
|
1078 temp = int(a.get("maxdex"))
|
|
1079 if temp < dex: dex = temp
|
|
1080 return dex
|
|
1081
|
|
1082 def get_total(self,attr):
|
|
1083 armor_list = self.xml.findall('armor')
|
|
1084 total = 0
|
|
1085 for a in armor_list: total += int(a.get(attr))
|
|
1086 return total
|
|
1087
|
|
1088 def get_design_panel(self,parent):
|
|
1089 wnd = outline_panel(parent,self,ac_panel,"Armor")
|
|
1090 wnd.title = "Armor"
|
|
1091 return wnd
|
|
1092
|
|
1093 def tohtml(self):
|
|
1094 html_str = """<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>AC</th>
|
|
1095 <th>Check Penalty</th><th >Spell Failure</th><th>Max Dex</th><th>Total Weight</th></tr>"""
|
|
1096 html_str += "<tr ALIGN='center' ><td>"+str(self.get_armor_class())+"</td>"
|
|
1097 html_str += "<td>"+str(self.get_check_pen())+"</td>"
|
|
1098 html_str += "<td>"+str(self.get_spell_failure())+"</td>"
|
|
1099 html_str += "<td>"+str(self.get_max_dex())+"</td>"
|
|
1100 html_str += "<td>"+str(self.get_total_weight())+"</td></tr></table>"
|
|
1101 for n in self.xml:
|
|
1102 html_str += """<P><table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th colspan=3>Armor</th>
|
|
1103 <th>Type</th><th >Bonus</th></tr>"""
|
|
1104 html_str += "<tr ALIGN='center' ><td colspan=3>"+n.get('name')+"</td>"
|
|
1105 html_str += "<td>"+n.get('type')+"</td>"
|
|
1106 html_str += "<td>"+n.get('bonus')+"</td></tr>"
|
|
1107 html_str += """<tr BGCOLOR=#E9E9E9 ><th>Check Penalty</th><th>Spell Failure</th>
|
|
1108 <th>Max Dex</th><th>Speed</th><th>Weight</th></tr>"""
|
|
1109 html_str += "<tr ALIGN='center'><td>"+n.get('checkpenalty')+"</td>"
|
|
1110 html_str += "<td>"+n.get('spellfailure')+"</td>"
|
|
1111 html_str += "<td>"+n.get('maxdex')+"</td>"
|
|
1112 html_str += "<td>"+n.get('speed')+"</td>"
|
|
1113 html_str += "<td>"+n.get('weight')+"</td></tr></table>"
|
|
1114 return html_str
|
|
1115
|
|
1116
|
|
1117 ########################
|
|
1118 ## d20 char windows
|
|
1119 ########################
|
|
1120
|
|
1121 class base_panel(wx.Panel):
|
|
1122 def __init__(self, parent):
|
|
1123 wx.Panel.__init__(self, parent, -1)
|
|
1124
|
|
1125 #self.build_ctrls()
|
|
1126 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1127
|
|
1128 def on_size(self,event):
|
|
1129 s = self.GetClientSizeTuple()
|
|
1130 #self.splitter.SetDimensions(0,0,s[0],s[1])
|
|
1131
|
|
1132 class outline_panel(wx.Panel):
|
|
1133 def __init__(self, parent, handler, wnd, txt,):
|
|
1134 wx.Panel.__init__(self, parent, -1)
|
|
1135 self.panel = wnd(self,handler)
|
|
1136 self.outline = wx.StaticBox(self,-1,txt)
|
|
1137 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1138
|
|
1139 def on_size(self,event):
|
|
1140 s = self.GetClientSizeTuple()
|
|
1141 self.panel.SetDimensions(20,20,s[0]-40,s[1]-40)
|
|
1142 self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
|
|
1143
|
|
1144 class char_panel(wx.ScrolledWindow):
|
|
1145 def __init__(self, parent, handler):
|
|
1146 pname = handler.xml.set("name", 'TWO')
|
|
1147 wx.ScrolledWindow.__init__(self, parent, -1,style=wx.VSCROLL | wx.SUNKEN_BORDER )
|
|
1148 self.height = 1200
|
|
1149 self.SetScrollbars(10, 10,80, self.height/10)
|
|
1150 self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1151 self.panels = {}
|
|
1152 keys = handler.child_handlers.keys()
|
|
1153 for k in keys: self.panels[k] = handler.child_handlers[k].get_design_panel(self, [k])
|
|
1154 self.sub_sizer = wx.BoxSizer(wx.VERTICAL)
|
|
1155 self.sub_sizer2 = wx.BoxSizer(wx.VERTICAL)
|
|
1156 self.sub_sizer.Add(self.panels['general'], 1, wx.EXPAND)
|
|
1157 self.sub_sizer.Add(self.panels['abilities'], 1, wx.EXPAND)
|
|
1158
|
|
1159 self.sub_sizer.Add(self.panels['attacks'], 2, wx.EXPAND)
|
|
1160 self.sub_sizer.Add(self.panels['ac'], 1, wx.EXPAND)
|
|
1161 self.sub_sizer.Add(self.panels['spells'], 1, wx.EXPAND)
|
|
1162
|
|
1163 self.sub_sizer2.Add(self.panels['classes'], 2, wx.EXPAND)
|
|
1164 self.sub_sizer2.Add(self.panels['hp'], 1, wx.EXPAND)
|
|
1165 self.sub_sizer2.Add(self.panels['pp'], 1, wx.EXPAND)
|
|
1166 self.sub_sizer2.Add(self.panels['saves'], 2, wx.EXPAND)
|
|
1167
|
|
1168 self.sub_sizer2.Add(self.panels['feats'], 2, wx.EXPAND)
|
|
1169 self.sub_sizer2.Add(self.panels['powers'], 2, wx.EXPAND)
|
|
1170 self.sub_sizer2.Add(self.panels['skills'], 3, wx.EXPAND)
|
|
1171
|
|
1172 self.main_sizer.Add(self.sub_sizer, 1, wx.EXPAND)
|
|
1173 self.main_sizer.Add(self.sub_sizer2, 1, wx.EXPAND)
|
|
1174 self.panels['abilities'].panel.char_wnd = self
|
|
1175 self.SetSizer(self.main_sizer)
|
|
1176 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1177
|
|
1178
|
|
1179 def on_size(self,evt):
|
|
1180 s = self.GetClientSizeTuple()
|
|
1181 self.SetScrollbars(10, 10,s[0]/10, self.height/10)
|
|
1182 dc = wx.ClientDC(self)
|
|
1183 x = dc.DeviceToLogicalX(0)
|
|
1184 y = dc.DeviceToLogicalY(0)
|
|
1185 self.main_sizer.SetDimension(x,y,s[0],self.height)
|
|
1186 evt.Skip()
|
|
1187
|
|
1188 def refresh_data(self):
|
|
1189 self.panels['saves'].panel.refresh_data()
|
|
1190 self.panels['skills'].panel.refresh_data()
|
|
1191 self.panels['attacks'].panel.refresh_data()
|
|
1192 self.panels['powers'].panel.refresh_data()
|
|
1193 self.panels['spells'].panel.refresh_data()
|
|
1194
|
|
1195 HOWTO_MAX = wx.NewId()
|
|
1196
|
|
1197 class howto_panel(wx.Panel):
|
|
1198 def __init__(self, parent, handler):
|
|
1199 wx.Panel.__init__(self, parent, -1)
|
|
1200 pname = handler.xml.set("name", 'How To')
|
|
1201 self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap
|
|
1202 self.sizer.AddMany([ (wx.StaticText(self, -1,
|
|
1203 handler.xml.find('howto').text),
|
|
1204 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1205 ])
|
|
1206 self.sizer.AddGrowableCol(1)
|
|
1207 self.SetSizer(self.sizer)
|
|
1208
|
|
1209
|
|
1210 HP_CUR = wx.NewId()
|
|
1211 HP_MAX = wx.NewId()
|
|
1212
|
|
1213 class hp_panel(wx.Panel):
|
|
1214 def __init__(self, parent, handler):
|
|
1215 wx.Panel.__init__(self, parent, -1)
|
|
1216 pname = handler.xml.set("name", 'HitPoints')
|
|
1217 self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap
|
|
1218 self.xml = handler.xml
|
|
1219 self.sizer.AddMany([ (wx.StaticText(self, -1, "HP Current:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1220 (wx.TextCtrl(self, HP_CUR, self.xml.get('current')), 0, wx.EXPAND),
|
|
1221 (wx.StaticText(self, -1, "HP Max:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1222 (wx.TextCtrl(self, HP_MAX, self.xml.get('max')), 0, wx.EXPAND),
|
|
1223 ])
|
|
1224 self.sizer.AddGrowableCol(1)
|
|
1225 self.SetSizer(self.sizer)
|
|
1226 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1227 self.Bind(wx.EVT_TEXT, self.on_text, id=HP_MAX)
|
|
1228 self.Bind(wx.EVT_TEXT, self.on_text, id=HP_CUR)
|
|
1229
|
|
1230 def on_text(self,evt):
|
|
1231 id = evt.GetId()
|
|
1232 if id == HP_CUR: self.xml.set('current',evt.GetString())
|
|
1233 elif id == HP_MAX: self.xml.set('max',evt.GetString())
|
|
1234
|
|
1235 def on_size(self,evt):
|
|
1236 s = self.GetClientSizeTuple()
|
|
1237 self.sizer.SetDimension(0,0,s[0],s[1])
|
|
1238
|
|
1239 PP_CUR = wx.NewId()
|
|
1240 PP_MAX = wx.NewId()
|
|
1241 PP_FRE = wx.NewId()
|
|
1242 PP_MFRE = wx.NewId()
|
|
1243
|
|
1244 class pp_panel(wx.Panel):
|
|
1245 def __init__(self, parent, handler):
|
|
1246 wx.Panel.__init__(self, parent, -1)
|
|
1247 pname = handler.xml.set("name", 'PowerPoints')
|
|
1248 self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap
|
|
1249 self.xml = handler.xml
|
|
1250
|
|
1251 self.sizer.AddMany([ (wx.StaticText(self, -1, "PP Current:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1252 (wx.TextCtrl(self, PP_CUR, self.xml.get('current1')), 0, wx.EXPAND),
|
|
1253 (wx.StaticText(self, -1, "PP Max:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1254 (wx.TextCtrl(self, PP_MAX, self.xml.get('max1')), 0, wx.EXPAND),
|
|
1255 (wx.StaticText(self, -1, "Current Free Talants per day:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1256 (wx.TextCtrl(self, PP_FRE, self.xml.get('free')), 0, wx.EXPAND),
|
|
1257 (wx.StaticText(self, -1, "Max Free Talants per day:"), 0, wx.ALIGN_CENTER_VERTICAL),
|
|
1258 (wx.TextCtrl(self, PP_MFRE, self.xml.get('maxfree')), 0, wx.EXPAND),
|
|
1259 ])
|
|
1260 self.sizer.AddGrowableCol(1)
|
|
1261 self.SetSizer(self.sizer)
|
|
1262 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1263 self.Bind(wx.EVT_TEXT, self.on_text, id=PP_MAX)
|
|
1264 self.Bind(wx.EVT_TEXT, self.on_text, id=PP_CUR)
|
|
1265 self.Bind(wx.EVT_TEXT, self.on_text, id=PP_FRE)
|
|
1266 self.Bind(wx.EVT_TEXT, self.on_text, id=PP_MFRE)
|
|
1267
|
|
1268 def on_text(self,evt):
|
|
1269 id = evt.GetId()
|
|
1270 if id == PP_CUR: self.xml.set('current1',evt.GetString())
|
|
1271 elif id == PP_MAX: self.xml.set('max1',evt.GetString())
|
|
1272 elif id == PP_FRE: self.xml.set('free',evt.GetString())
|
|
1273 elif id == PP_MFRE: self.xml.set('maxfree',evt.GetString())
|
|
1274
|
|
1275 def on_size(self,evt):
|
|
1276 s = self.GetClientSizeTuple()
|
|
1277 self.sizer.SetDimension(0,0,s[0],s[1])
|
|
1278
|
|
1279
|
|
1280 class gen_grid(wx.grid.Grid):
|
|
1281 """grid for gen info"""
|
|
1282 def __init__(self, parent, handler):
|
|
1283 pname = handler.xml.set("name", 'General')
|
|
1284 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1285 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1286 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1287 self.handler = handler
|
|
1288 n_list = handler.xml[:]
|
|
1289 self.CreateGrid(len(n_list),2)
|
|
1290 self.SetRowLabelSize(0)
|
|
1291 self.SetColLabelSize(0)
|
|
1292 self.n_list = n_list
|
|
1293 i = 0
|
|
1294 for i in range(len(n_list)): self.refresh_row(i)
|
|
1295
|
|
1296 def on_cell_change(self,evt):
|
|
1297 row = evt.GetRow()
|
|
1298 col = evt.GetCol()
|
|
1299 value = self.GetCellValue(row,col)
|
|
1300 self.n_list[row].text = value
|
|
1301 if row==0: self.handler.on_name_change(value)
|
|
1302
|
|
1303 def refresh_row(self,rowi):
|
|
1304 self.SetCellValue(rowi,0,self.n_list[rowi].tag)
|
|
1305 self.SetReadOnly(rowi,0)
|
|
1306 self.SetCellValue(rowi,1,self.n_list[rowi].text)
|
|
1307
|
|
1308 def on_size(self,evt):
|
|
1309 (w,h) = self.GetClientSizeTuple()
|
|
1310 cols = self.GetNumberCols()
|
|
1311 col_w = w/(cols)
|
|
1312 for i in range(0,cols): self.SetColSize(i,col_w)
|
|
1313 evt.Skip()
|
|
1314 self.Refresh()
|
|
1315
|
|
1316 class inventory_grid(wx.grid.Grid):
|
|
1317 """grid for gen info"""
|
|
1318 def __init__(self, parent, handler):
|
|
1319 pname = handler.xml.set("name", 'Money and Inventory')
|
|
1320 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1321 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1322 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1323 self.handler = handler
|
|
1324 n_list = handler.xml[:]
|
|
1325 self.CreateGrid(len(n_list),2)
|
|
1326 self.SetRowLabelSize(0)
|
|
1327 self.SetColLabelSize(0)
|
|
1328 self.n_list = n_list
|
|
1329 i = 0
|
|
1330 for i in range(len(n_list)): self.refresh_row(i)
|
|
1331
|
|
1332 def on_cell_change(self,evt):
|
|
1333 row = evt.GetRow()
|
|
1334 col = evt.GetCol()
|
|
1335 value = self.GetCellValue(row,col)
|
|
1336 self.n_list[row].text = value
|
|
1337 if row==0: self.handler.on_name_change(value)
|
|
1338
|
|
1339 def refresh_row(self,rowi):
|
|
1340 self.SetCellValue(rowi,0,self.n_list[rowi].tag)
|
|
1341 self.SetReadOnly(rowi,0)
|
|
1342 self.SetCellValue(rowi,1,self.n_list[rowi].text)
|
|
1343
|
|
1344 def on_size(self,evt):
|
|
1345 (w,h) = self.GetClientSizeTuple()
|
|
1346 cols = self.GetNumberCols()
|
|
1347 col_w = w/(cols)
|
|
1348 for i in range(0,cols): self.SetColSize(i,col_w)
|
|
1349 evt.Skip()
|
|
1350 self.Refresh()
|
|
1351
|
|
1352 class abil_grid(wx.grid.Grid):
|
|
1353 """grid for abilities"""
|
|
1354 def __init__(self, parent, handler):
|
|
1355 pname = handler.xml.set("name", 'Stats')
|
|
1356 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1357 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1358 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1359 self.handler = handler
|
|
1360 stats = handler.xml.findall('stat')
|
|
1361 self.CreateGrid(len(stats),3)
|
|
1362 self.SetRowLabelSize(0)
|
|
1363 col_names = ['Ability','Score','Modifier']
|
|
1364 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i])
|
|
1365 self.stats = stats
|
|
1366 i = 0
|
|
1367 for i in range(len(stats)): self.refresh_row(i)
|
|
1368 self.char_wnd = None
|
|
1369
|
|
1370 def on_cell_change(self,evt):
|
|
1371 row = evt.GetRow()
|
|
1372 col = evt.GetCol()
|
|
1373 value = self.GetCellValue(row,col)
|
|
1374 try:
|
|
1375 int(value)
|
|
1376 self.stats[row].set('base',value)
|
|
1377 self.refresh_row(row)
|
|
1378 except: self.SetCellValue(row,col,"0")
|
|
1379 if self.char_wnd: self.char_wnd.refresh_data()
|
|
1380
|
|
1381 def refresh_row(self,rowi):
|
|
1382 s = self.stats[rowi]
|
|
1383 name = s.get('name')
|
|
1384 abbr = s.get('abbr')
|
|
1385 self.SetCellValue(rowi,0,name)
|
|
1386 self.SetReadOnly(rowi,0)
|
|
1387 self.SetCellValue(rowi,1,s.get('base'))
|
|
1388 self.SetCellValue(rowi,2,str(self.handler.get_mod(abbr)))
|
|
1389 self.SetReadOnly(rowi,2)
|
|
1390
|
|
1391 def on_size(self,evt):
|
|
1392 (w,h) = self.GetClientSizeTuple()
|
|
1393 cols = self.GetNumberCols()
|
|
1394 col_w = w/(cols+2)
|
|
1395 self.SetColSize(0,col_w*3)
|
|
1396 for i in range(1,cols): self.SetColSize(i,col_w)
|
|
1397 evt.Skip()
|
|
1398 self.Refresh()
|
|
1399
|
|
1400 def refresh_data(self):
|
|
1401 for r in range(self.GetNumberRows()-1): self.refresh_row(r)
|
|
1402
|
|
1403
|
|
1404 class save_grid(wx.grid.Grid):
|
|
1405 """grid for saves"""
|
|
1406 def __init__(self, parent, handler):
|
|
1407 pname = handler.xml.set("name", 'Saves')
|
|
1408 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1409 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1410 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1411 self.handler = handler
|
|
1412 saves = handler.xml.findall('save')
|
|
1413 self.stats = handler.char_hander.child_handlers['abilities']
|
|
1414 self.CreateGrid(len(saves),7)
|
|
1415 self.SetRowLabelSize(0)
|
|
1416 col_names = ['Save','Key','base','Abil','Magic','Misc','Total']
|
|
1417 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i])
|
|
1418 self.saves = saves
|
|
1419 i = 0
|
|
1420 for i in range(len(saves)): self.refresh_row(i)
|
|
1421
|
|
1422 def on_cell_change(self,evt):
|
|
1423 row = evt.GetRow()
|
|
1424 col = evt.GetCol()
|
|
1425 value = self.GetCellValue(row,col)
|
|
1426 try:
|
|
1427 int(value)
|
|
1428 if col == 2: self.saves[row].set('base',value)
|
|
1429 elif col == 4: self.saves[row].set('magmod',value)
|
|
1430 elif col == 4: self.saves[row].set('miscmod',value)
|
|
1431 self.refresh_row(row)
|
|
1432 except: self.SetCellValue(row,col,"0")
|
|
1433
|
|
1434 def refresh_row(self,rowi):
|
|
1435 s = self.saves[rowi]
|
|
1436 name = s.get('name')
|
|
1437 self.SetCellValue(rowi,0,name)
|
|
1438 self.SetReadOnly(rowi,0)
|
|
1439 stat = s.get('stat')
|
|
1440 self.SetCellValue(rowi,1,stat)
|
|
1441 self.SetReadOnly(rowi,1)
|
|
1442 self.SetCellValue(rowi,2,s.get('base'))
|
|
1443 self.SetCellValue(rowi,3,str(self.stats.get_mod(stat)))
|
|
1444 self.SetReadOnly(rowi,3)
|
|
1445 self.SetCellValue(rowi,4,s.get('magmod'))
|
|
1446 self.SetCellValue(rowi,5,s.get('miscmod'))
|
|
1447 mod = str(self.handler.get_mod(name))
|
|
1448 self.SetCellValue(rowi,6,mod)
|
|
1449 self.SetReadOnly(rowi,6)
|
|
1450
|
|
1451 def on_size(self,evt):
|
|
1452 (w,h) = self.GetClientSizeTuple()
|
|
1453 cols = self.GetNumberCols()
|
|
1454 col_w = w/(cols+2)
|
|
1455 self.SetColSize(0,col_w*3)
|
|
1456 for i in range(1,cols): self.SetColSize(i,col_w)
|
|
1457 evt.Skip()
|
|
1458 self.Refresh()
|
|
1459
|
|
1460 def refresh_data(self):
|
|
1461 for r in range(self.GetNumberRows()): self.refresh_row(r)
|
|
1462
|
|
1463
|
|
1464 class skill_grid(wx.grid.Grid):
|
|
1465 """ panel for skills """
|
|
1466 def __init__(self, parent, handler):
|
|
1467 pname = handler.xml.set("name", 'Skills')
|
|
1468 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1469 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1470 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1471 self.handler = handler
|
|
1472 skills = handler.xml.findall('skill')
|
|
1473 self.stats = handler.char_hander.child_handlers['abilities']
|
|
1474 self.CreateGrid(len(skills),6)
|
|
1475 self.SetRowLabelSize(0)
|
|
1476 col_names = ['Skill','Key','Rank','Abil','Misc','Total']
|
|
1477 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i])
|
|
1478 rowi = 0
|
|
1479 self.skills = skills
|
|
1480 for i in range(len(skills)): self.refresh_row(i)
|
|
1481
|
|
1482 def on_cell_change(self,evt):
|
|
1483 row = evt.GetRow()
|
|
1484 col = evt.GetCol()
|
|
1485 value = self.GetCellValue(row,col)
|
|
1486 try:
|
|
1487 int(value)
|
|
1488 if col == 2: self.skills[row].set('rank',value)
|
|
1489 elif col == 4: self.skills[row].set('misc',value)
|
|
1490 self.refresh_row(row)
|
|
1491 except: self.SetCellValue(row,col,"0")
|
|
1492
|
|
1493 def refresh_row(self,rowi):
|
|
1494 s = self.skills[rowi]
|
|
1495 name = s.get('name')
|
|
1496 self.SetCellValue(rowi,0,name)
|
|
1497 self.SetReadOnly(rowi,0)
|
|
1498 stat = s.get('stat')
|
|
1499 self.SetCellValue(rowi,1,stat)
|
|
1500 self.SetReadOnly(rowi,1)
|
|
1501 self.SetCellValue(rowi,2,s.get('rank'))
|
|
1502 self.SetCellValue(rowi,3,str(self.stats.get_mod(stat)))
|
|
1503 self.SetReadOnly(rowi,3)
|
|
1504 self.SetCellValue(rowi,4,s.get('misc'))
|
|
1505 mod = str(self.handler.get_mod(name))
|
|
1506 self.SetCellValue(rowi,5,mod)
|
|
1507 self.SetReadOnly(rowi,5)
|
|
1508
|
|
1509 def on_size(self,evt):
|
|
1510 (w,h) = self.GetClientSizeTuple()
|
|
1511 cols = self.GetNumberCols()
|
|
1512 col_w = w/(cols+2)
|
|
1513 self.SetColSize(0,col_w*3)
|
|
1514 for i in range(1,cols): self.SetColSize(i,col_w)
|
|
1515 evt.Skip()
|
|
1516 self.Refresh()
|
|
1517
|
|
1518 def refresh_data(self):
|
|
1519 for r in range(self.GetNumberRows()): self.refresh_row(r)
|
|
1520
|
|
1521
|
|
1522 class feat_panel(wx.Panel):
|
|
1523 def __init__(self, parent, handler):
|
|
1524 pname = handler.xml.set("name", 'Feats')
|
|
1525 wx.Panel.__init__(self, parent, -1)
|
|
1526 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1527 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1528 sizer.Add(wx.Button(self, 10, "Remove Feat"), 1, wx.EXPAND)
|
|
1529 sizer.Add(wx.Size(10,10))
|
|
1530 sizer.Add(wx.Button(self, 20, "Add Feat"), 1, wx.EXPAND)
|
|
1531 self.sizer = sizer
|
|
1532 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1533 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
1534 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
1535
|
|
1536 n_list = handler.xml[:]
|
|
1537 self.n_list = n_list
|
|
1538 self.xml = handler.xml
|
|
1539 self.grid.CreateGrid(len(n_list),2,1)
|
|
1540 self.grid.SetRowLabelSize(0)
|
|
1541 self.grid.SetColLabelValue(0,"Feat")
|
|
1542 self.grid.SetColLabelValue(1,"Type")
|
|
1543 for i in range(len(n_list)): self.refresh_row(i)
|
|
1544 self.temp_dom = None
|
|
1545 self.SetSizer(self.sizer)
|
|
1546
|
|
1547 def refresh_row(self,i):
|
|
1548 feat = self.n_list[i]
|
|
1549 name = feat.get('name')
|
|
1550 type = feat.get('type')
|
|
1551 self.grid.SetCellValue(i,0,name)
|
|
1552 self.grid.SetReadOnly(i,0)
|
|
1553 self.grid.SetCellValue(i,1,type)
|
|
1554 self.grid.SetReadOnly(i,1)
|
|
1555
|
|
1556 def on_remove(self,evt):
|
|
1557 rows = self.grid.GetNumberRows()
|
|
1558 for i in range(rows):
|
|
1559 if self.grid.IsInSelection(i,0):
|
|
1560 self.grid.DeleteRows(i)
|
|
1561 self.xml.removeChild(self.n_list[i])
|
|
1562
|
|
1563 def on_add(self,evt):
|
|
1564 if not self.temp_dom:
|
|
1565 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20feats.xml")
|
|
1566 self.temp_dom = tree.getroot()
|
|
1567 f_list = self.temp_dom.findall('feat')
|
|
1568 opts = []
|
|
1569 for f in f_list: opts.append(f.get('name'))
|
|
1570 dlg = wx.SingleChoiceDialog(self,'Choose Feat','Feats',opts)
|
|
1571 if dlg.ShowModal() == wx.ID_OK:
|
|
1572 i = dlg.GetSelection()
|
|
1573 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
1574 self.grid.AppendRows(1)
|
|
1575 self.n_list = self.xml.findall('feat')
|
|
1576 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
1577 dlg.Destroy()
|
|
1578
|
|
1579 def on_size(self,event):
|
|
1580 s = self.GetClientSizeTuple()
|
|
1581 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
1582 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
1583 (w,h) = self.grid.GetClientSizeTuple()
|
|
1584 cols = self.grid.GetNumberCols()
|
|
1585 col_w = w/(cols)
|
|
1586 for i in range(0,cols): self.grid.SetColSize(i,col_w)
|
|
1587
|
|
1588 class spell_panel(wx.Panel):
|
|
1589 def __init__(self, parent, handler):
|
|
1590 pname = handler.xml.set("name", 'Arcane Spells')
|
|
1591 wx.Panel.__init__(self, parent, -1)
|
|
1592 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1593 self.handler = handler
|
|
1594 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1595 sizer.Add(wx.Button(self, 10, "Remove Spell"), 1, wx.EXPAND)
|
|
1596 sizer.Add(wx.Size(10,10))
|
|
1597 sizer.Add(wx.Button(self, 20, "Add Spell"), 1, wx.EXPAND)
|
|
1598 sizer.Add(wx.Size(10,10))
|
|
1599 sizer.Add(wx.Button(self, 30, "Refresh Spells"), 1, wx.EXPAND)
|
|
1600 self.sizer = sizer
|
|
1601 self.SetSizer(self.sizer)
|
|
1602 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1603 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
1604 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
1605 self.Bind(wx.EVT_BUTTON, self.on_refresh_spells, id=30)
|
|
1606 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1607 n_list = handler.xml[:]
|
|
1608 self.n_list = n_list
|
|
1609 self.xml = handler.xml
|
|
1610 self.grid.CreateGrid(len(n_list),4,1)
|
|
1611 self.grid.SetRowLabelSize(0)
|
|
1612 self.grid.SetColLabelValue(0,"No.")
|
|
1613 self.grid.SetColLabelValue(1,"Lvl")
|
|
1614 self.grid.SetColLabelValue(2,"Spell")
|
|
1615 self.grid.SetColLabelValue(3,"Desc")
|
|
1616 for i in range(len(n_list)): self.refresh_row(i)
|
|
1617 self.temp_dom = None
|
|
1618
|
|
1619 def on_cell_change(self,evt):
|
|
1620 row = evt.GetRow()
|
|
1621 col = evt.GetCol()
|
|
1622 value = self.grid.GetCellValue(row,col)
|
|
1623 if col == 0: self.n_list[row].set('memrz',value)
|
|
1624
|
|
1625 def refresh_row(self,i):
|
|
1626 spell = self.n_list[i]
|
|
1627 memrz = spell.get('memrz')
|
|
1628 name = spell.get('name')
|
|
1629 type = spell.get('desc')
|
|
1630 level = spell.get('level')
|
|
1631 self.grid.SetCellValue(i,0,memrz)
|
|
1632 self.grid.SetCellValue(i,2,name)
|
|
1633 self.grid.SetReadOnly(i,2)
|
|
1634 self.grid.SetCellValue(i,3,type)
|
|
1635 self.grid.SetReadOnly(i,3)
|
|
1636 self.grid.SetCellValue(i,1,level)
|
|
1637 self.grid.SetReadOnly(i,1)
|
|
1638
|
|
1639 def on_remove(self,evt):
|
|
1640 rows = self.grid.GetNumberRows()
|
|
1641 for i in range(rows):
|
|
1642 if self.grid.IsInSelection(i,0):
|
|
1643 self.grid.DeleteRows(i)
|
|
1644 self.xml.removeChild(self.n_list[i])
|
|
1645 self.handler.refresh_spells()
|
|
1646
|
|
1647 def on_add(self,evt):
|
|
1648 if not self.temp_dom:
|
|
1649 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20spells.xml")
|
|
1650 self.temp_dom = tree.getroot()
|
|
1651 f_list = self.temp_dom.findall('spell')
|
|
1652 opts = []
|
|
1653 for f in f_list: opts.append("(" + f.get('level') + ")" + f.get('name'))
|
|
1654 dlg = wx.SingleChoiceDialog(self,'Choose Spell','Spells',opts)
|
|
1655 if dlg.ShowModal() == wx.ID_OK:
|
|
1656 i = dlg.GetSelection()
|
|
1657 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
1658 self.grid.AppendRows(1)
|
|
1659 self.n_list = self.xml.findall('spell')
|
|
1660 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
1661 self.handler.refresh_spells()
|
|
1662 dlg.Destroy()
|
|
1663
|
|
1664 def on_refresh_spells( self, evt ):
|
|
1665 f_list = self.xml.findall('spell')
|
|
1666 for spell in f_list: spell.set( 'used', '0' )
|
|
1667
|
|
1668 def on_size(self,event):
|
|
1669 s = self.GetClientSizeTuple()
|
|
1670 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
1671 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
1672 (w,h) = self.grid.GetClientSizeTuple()
|
|
1673 cols = self.grid.GetNumberCols()
|
|
1674 col_w = w/(cols)
|
|
1675 for i in range(0,cols): self.grid.SetColSize(i,col_w)
|
|
1676 self.grid.SetColSize(0,w * 0.10)
|
|
1677 self.grid.SetColSize(1,w * 0.10)
|
|
1678 self.grid.SetColSize(2,w * 0.30)
|
|
1679 self.grid.SetColSize(3,w * 0.50)
|
|
1680
|
|
1681 def refresh_data(self):
|
|
1682 for i in range(len(self.n_list)): self.refresh_row(i)
|
|
1683
|
|
1684 class divine_panel(wx.Panel):
|
|
1685 def __init__(self, parent, handler):
|
|
1686 pname = handler.xml.set("name", 'Divine Spells')
|
|
1687 wx.Panel.__init__(self, parent, -1)
|
|
1688 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1689 self.handler = handler
|
|
1690 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1691 sizer.Add(wx.Button(self, 10, "Remove Spell"), 1, wx.EXPAND)
|
|
1692 sizer.Add(wx.Size(10,10))
|
|
1693 sizer.Add(wx.Button(self, 20, "Add Spell"), 1, wx.EXPAND)
|
|
1694 sizer.Add(wx.Size(10,10))
|
|
1695 sizer.Add(wx.Button(self, 30, "Refresh Spells"), 1, wx.EXPAND)
|
|
1696 self.sizer = sizer
|
|
1697 self.SetSizer(self.sizer)
|
|
1698 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1699 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
1700 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
1701 self.Bind(wx.EVT_BUTTON, self.on_refresh_spells, id=30)
|
|
1702 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1703 n_list = handler.xml[:]
|
|
1704 self.n_list = n_list
|
|
1705 self.xml = handler.xml
|
|
1706 self.grid.CreateGrid(len(n_list),4,1)
|
|
1707 self.grid.SetRowLabelSize(0)
|
|
1708 self.grid.SetColLabelValue(0,"No.")
|
|
1709 self.grid.SetColLabelValue(1,"Lvl")
|
|
1710 self.grid.SetColLabelValue(2,"Spell")
|
|
1711 self.grid.SetColLabelValue(3,"Desc")
|
|
1712 for i in range(len(n_list)): self.refresh_row(i)
|
|
1713 self.temp_dom = None
|
|
1714
|
|
1715 def on_cell_change(self,evt):
|
|
1716 row = evt.GetRow()
|
|
1717 col = evt.GetCol()
|
|
1718 value = self.grid.GetCellValue(row,col)
|
|
1719 if col == 0: self.n_list[row].set('memrz',value)
|
|
1720
|
|
1721
|
|
1722 def refresh_row(self,i):
|
|
1723 spell = self.n_list[i]
|
|
1724 memrz = spell.get('memrz')
|
|
1725 name = spell.get('name')
|
|
1726 type = spell.get('desc')
|
|
1727 level = spell.get('level')
|
|
1728 self.grid.SetCellValue(i,0,memrz)
|
|
1729 self.grid.SetCellValue(i,2,name)
|
|
1730 self.grid.SetReadOnly(i,2)
|
|
1731 self.grid.SetCellValue(i,3,type)
|
|
1732 self.grid.SetReadOnly(i,3)
|
|
1733 self.grid.SetCellValue(i,1,level)
|
|
1734 self.grid.SetReadOnly(i,1)
|
|
1735
|
|
1736 def on_remove(self,evt):
|
|
1737 rows = self.grid.GetNumberRows()
|
|
1738 for i in range(rows):
|
|
1739 if self.grid.IsInSelection(i,0):
|
|
1740 self.grid.DeleteRows(i)
|
|
1741 self.xml.remove(self.n_list[i])
|
|
1742 self.handler.refresh_spells()
|
|
1743
|
|
1744 def on_add(self,evt):
|
|
1745 if not self.temp_dom:
|
|
1746 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20divine.xml")
|
|
1747 self.temp_dom = tree.getroot()
|
|
1748 f_list = self.temp_dom.findall('gift')
|
|
1749 opts = []
|
|
1750 for f in f_list: opts.append("(" + f.get('level') + ")" + f.get('name'))
|
|
1751 dlg = wx.SingleChoiceDialog(self,'Choose Spell','Spells',opts)
|
|
1752 if dlg.ShowModal() == wx.ID_OK:
|
|
1753 i = dlg.GetSelection()
|
|
1754 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
1755 self.grid.AppendRows(1)
|
|
1756 self.n_list = self.xml.findall('gift')
|
|
1757 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
1758 self.handler.refresh_spells()
|
|
1759 dlg.Destroy()
|
|
1760
|
|
1761 def on_refresh_spells( self, evt ):
|
|
1762 f_list = self.xml.findall('gift')
|
|
1763 for spell in f_list: spell.set( 'used', '0' )
|
|
1764
|
|
1765 def on_size(self,event):
|
|
1766 s = self.GetClientSizeTuple()
|
|
1767 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
1768 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
1769 (w,h) = self.grid.GetClientSizeTuple()
|
|
1770 cols = self.grid.GetNumberCols()
|
|
1771 col_w = w/(cols)
|
|
1772 for i in range(0,cols): self.grid.SetColSize(i,col_w)
|
|
1773 self.grid.SetColSize(0,w * 0.10)
|
|
1774 self.grid.SetColSize(1,w * 0.10)
|
|
1775 self.grid.SetColSize(2,w * 0.30)
|
|
1776 self.grid.SetColSize(3,w * 0.50)
|
|
1777
|
|
1778 def refresh_data(self):
|
|
1779 for i in range(len(self.n_list)): self.refresh_row(i)
|
|
1780
|
|
1781
|
|
1782 class power_panel(wx.Panel):
|
|
1783 def __init__(self, parent, handler):
|
|
1784 pname = handler.xml.set("name", 'Pionic Powers')
|
|
1785 wx.Panel.__init__(self, parent, -1)
|
|
1786 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1787 self.handler = handler
|
|
1788 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1789 sizer.Add(wx.Button(self, 10, "Remove Power"), 1, wx.EXPAND)
|
|
1790 sizer.Add(wx.Size(10,10))
|
|
1791 sizer.Add(wx.Button(self, 20, "Add Power"), 1, wx.EXPAND)
|
|
1792 sizer.Add(wx.Size(10,10))
|
|
1793 sizer.Add(wx.Button(self, 30, "Refresh Powers"), 1, wx.EXPAND)
|
|
1794 self.sizer = sizer
|
|
1795 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1796 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
1797 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
1798 self.Bind(wx.EVT_BUTTON, self.on_refresh_powers, id=30)
|
|
1799 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1800 n_list = handler.xml[:]
|
|
1801 self.n_list = n_list
|
|
1802 self.xml = handler.xml
|
|
1803 self.grid.CreateGrid(len(n_list),5,1)
|
|
1804 self.grid.SetRowLabelSize(0)
|
|
1805 self.grid.SetColLabelValue(0,"PP")
|
|
1806 self.grid.SetColLabelValue(1,"Lvl")
|
|
1807 self.grid.SetColLabelValue(2,"Power")
|
|
1808 self.grid.SetColLabelValue(3,"Desc")
|
|
1809 self.grid.SetColLabelValue(4,"Type")
|
|
1810 for i in range(len(n_list)): self.refresh_row(i)
|
|
1811 self.refresh_data()
|
|
1812 self.temp_dom = None
|
|
1813 self.SetSizer(self.sizer)
|
|
1814
|
|
1815 def on_cell_change(self,evt):
|
|
1816 row = evt.GetRow()
|
|
1817 col = evt.GetCol()
|
|
1818 value = self.grid.GetCellValue(row,col)
|
|
1819
|
|
1820 def refresh_row(self,i):
|
|
1821 power = self.n_list[i]
|
|
1822 point = power.get('point')
|
|
1823 name = power.get('name')
|
|
1824 type = power.get('desc')
|
|
1825 test = power.get('test')
|
|
1826 level = power.get('level')
|
|
1827 self.grid.SetCellValue(i,0,point)
|
|
1828 self.grid.SetReadOnly(i,0)
|
|
1829 self.grid.SetCellValue(i,1,level)
|
|
1830 self.grid.SetReadOnly(i,1)
|
|
1831 self.grid.SetCellValue(i,2,name)
|
|
1832 self.grid.SetReadOnly(i,2)
|
|
1833 self.grid.SetCellValue(i,3,type)
|
|
1834 self.grid.SetReadOnly(i,3)
|
|
1835 self.grid.SetCellValue(i,4,test)
|
|
1836 self.grid.SetReadOnly(i,4)
|
|
1837
|
|
1838 def on_remove(self,evt):
|
|
1839 rows = self.grid.GetNumberRows()
|
|
1840 for i in range(rows):
|
|
1841 if self.grid.IsInSelection(i,0):
|
|
1842 self.grid.DeleteRows(i)
|
|
1843 self.xml.removeChild(self.n_list[i])
|
|
1844 self.handler.refresh_powers()
|
|
1845
|
|
1846 def on_add(self,evt):
|
|
1847 if not self.temp_dom:
|
|
1848 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20powers.xml")
|
|
1849 self.temp_dom = tree.getroot()
|
|
1850 f_list = self.temp_dom.findall('power')
|
|
1851 opts = []
|
|
1852 for f in f_list: opts.append("(" + f.get('level') + ") - " + f.get('name') + " - " + f.get('test'))
|
|
1853 dlg = wx.SingleChoiceDialog(self,'Choose Power','Powers',opts)
|
|
1854 if dlg.ShowModal() == wx.ID_OK:
|
|
1855 i = dlg.GetSelection()
|
|
1856 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
1857 self.grid.AppendRows(1)
|
|
1858 self.n_list = self.xml.findall('power')
|
|
1859 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
1860 self.handler.refresh_powers()
|
|
1861 dlg.Destroy()
|
|
1862
|
|
1863 def on_remove(self,evt):
|
|
1864 rows = self.grid.GetNumberRows()
|
|
1865 for i in range(rows):
|
|
1866 if self.grid.IsInSelection(i,0):
|
|
1867 self.grid.DeleteRows(i)
|
|
1868 self.xml.remove(self.n_list[i])
|
|
1869 self.n_list = self.xml.findall('weapon')
|
|
1870 self.handler.refresh_weapons()
|
|
1871
|
|
1872 def on_refresh_powers( self, evt ):
|
|
1873 mfre = self.handler.get_char_pp('maxfree')
|
|
1874 mpp = self.handler.get_char_pp('max1')
|
|
1875 self.handler.set_char_pp( 'free', mfre )
|
|
1876 self.handler.set_char_pp( 'current1', mpp )
|
|
1877
|
|
1878 def on_size(self,event):
|
|
1879 s = self.GetClientSizeTuple()
|
|
1880 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
1881 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
1882 (w,h) = self.grid.GetClientSizeTuple()
|
|
1883 cols = self.grid.GetNumberCols()
|
|
1884 col_w = w/(cols)
|
|
1885 for i in range(0,cols): self.grid.SetColSize(i,col_w)
|
|
1886 self.grid.SetColSize(0,w * 0.05)
|
|
1887 self.grid.SetColSize(1,w * 0.05)
|
|
1888 self.grid.SetColSize(2,w * 0.30)
|
|
1889 self.grid.SetColSize(3,w * 0.30)
|
|
1890 self.grid.SetColSize(4,w * 0.30)
|
|
1891
|
|
1892 def refresh_data(self):
|
|
1893 for i in range(len(self.n_list)): self.refresh_row(i)
|
|
1894
|
|
1895 class attack_grid(wx.grid.Grid):
|
|
1896 """grid for attacks"""
|
|
1897 def __init__(self, parent, handler):
|
|
1898 pname = handler.xml.set("name", 'Melee')
|
|
1899 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1900 self.parent = parent
|
|
1901 self.handler = handler
|
|
1902 self.babs = self.handler.melee
|
|
1903 self.CreateGrid(1,7)
|
|
1904 self.SetRowLabelSize(0)
|
|
1905 col_names = ['base','base 2','base 3','base 4','base 5','base 6','misc']
|
|
1906 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i])
|
|
1907 self.refresh_data()
|
|
1908 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1909 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1910
|
|
1911 def on_cell_change(self,evt):
|
|
1912 row = evt.GetRow()
|
|
1913 col = evt.GetCol()
|
|
1914 value = self.GetCellValue(row,col)
|
|
1915 try: int(value)
|
|
1916 except:
|
|
1917 value = "0"
|
|
1918 self.SetCellValue( row, col, value )
|
|
1919 attribs = ['base','second','third','forth','fifth','sixth','misc']
|
|
1920 self.babs.set( attribs[col], value )
|
|
1921 self.parent.refresh_data()
|
|
1922
|
|
1923 def refresh_data(self):
|
|
1924 attack_mods = self.handler.get_attack_data()
|
|
1925 for i in range(0,7): self.SetCellValue( 0, i, str(attack_mods[i]) )
|
|
1926
|
|
1927 def on_size(self,evt):
|
|
1928 (w,h) = self.GetClientSizeTuple()
|
|
1929 cols = self.GetNumberCols()
|
|
1930 col_w = w/cols
|
|
1931 for i in range(0,cols): self.SetColSize(i,col_w)
|
|
1932 evt.Skip()
|
|
1933 self.Refresh()
|
|
1934
|
|
1935 class weapon_panel(wx.Panel):
|
|
1936 def __init__(self, parent, handler):
|
|
1937 pname = handler.xml.set("name", 'Weapons')
|
|
1938 wx.Panel.__init__(self, parent, -1)
|
|
1939 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
1940 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
1941 sizer.Add(wx.Button(self, 10, "Remove Weapon"), 1, wx.EXPAND)
|
|
1942 sizer.Add(wx.Size(10,10))
|
|
1943 sizer.Add(wx.Button(self, 20, "Add Weapon"), 1, wx.EXPAND)
|
|
1944 self.sizer = sizer
|
|
1945 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
1946 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
1947 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
1948 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
1949 n_list = handler.xml.findall('weapon')
|
|
1950 self.n_list = n_list
|
|
1951 self.xml = handler.xml
|
|
1952 self.handler = handler
|
|
1953 self.grid.CreateGrid(len(n_list),8,1)
|
|
1954 self.grid.SetRowLabelSize(0)
|
|
1955 col_names = ['Name','damage','mod','critical','type','weight','range','size']
|
|
1956 for i in range(len(col_names)): self.grid.SetColLabelValue(i,col_names[i])
|
|
1957 self.refresh_data()
|
|
1958 self.temp_dom = None
|
|
1959 self.SetSizer(self.sizer)
|
|
1960
|
|
1961 def on_cell_change(self,evt):
|
|
1962 row = evt.GetRow()
|
|
1963 col = evt.GetCol()
|
|
1964 value = self.grid.GetCellValue(row,col)
|
|
1965 if col == 0:
|
|
1966 self.n_list[row].set('name',value)
|
|
1967 self.handler.refresh_weapons();
|
|
1968 else: self.n_list[row].set(self.grid.GetColLabelValue(col),value)
|
|
1969
|
|
1970 def refresh_row(self,i):
|
|
1971 n = self.n_list[i]
|
|
1972 name = n.get('name')
|
|
1973 mod = n.get('mod')
|
|
1974 ran = n.get('range')
|
|
1975 self.grid.SetCellValue(i,0,name)
|
|
1976 self.grid.SetCellValue(i,1,n.get('damage'))
|
|
1977 self.grid.SetCellValue(i,2,mod)
|
|
1978 self.grid.SetCellValue(i,3,n.get('critical'))
|
|
1979 self.grid.SetCellValue(i,4,n.get('type'))
|
|
1980 self.grid.SetCellValue(i,5,n.get('weight'))
|
|
1981 self.grid.SetCellValue(i,6,ran)
|
|
1982 self.grid.SetCellValue(i,7,n.get('size') )
|
|
1983
|
|
1984 def on_remove(self,evt):
|
|
1985 rows = self.grid.GetNumberRows()
|
|
1986 for i in range(rows):
|
|
1987 if self.grid.IsInSelection(i,0):
|
|
1988 self.grid.DeleteRows(i)
|
|
1989 self.xml.remove(self.n_list[i])
|
|
1990 self.n_list = self.xml.findall('weapon')
|
|
1991 self.handler.refresh_weapons()
|
|
1992
|
|
1993 def on_add(self,evt):
|
|
1994 if not self.temp_dom:
|
|
1995 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20weapons.xml")
|
|
1996 self.temp_dom = tree.getroot()
|
|
1997 f_list = self.temp_dom.findall('weapon')
|
|
1998 opts = []
|
|
1999 for f in f_list: opts.append(f.get('name'))
|
|
2000 dlg = wx.SingleChoiceDialog(self,'Choose Weapon','Weapon List',opts)
|
|
2001 if dlg.ShowModal() == wx.ID_OK:
|
|
2002 i = dlg.GetSelection()
|
|
2003 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
2004 self.grid.AppendRows(1)
|
|
2005 self.n_list = self.xml.findall('weapon')
|
|
2006 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
2007 self.handler.refresh_weapons()
|
|
2008 dlg.Destroy()
|
|
2009
|
|
2010 def on_size(self,event):
|
|
2011 s = self.GetClientSizeTuple()
|
|
2012 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
2013 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
2014 (w,h) = self.grid.GetClientSizeTuple()
|
|
2015 cols = self.grid.GetNumberCols()
|
|
2016 col_w = w/(cols+1)
|
|
2017 self.grid.SetColSize(0,col_w*2)
|
|
2018 for i in range(1,cols): self.grid.SetColSize(i,col_w)
|
|
2019
|
|
2020 def refresh_data(self):
|
|
2021 for i in range(len(self.n_list)): self.refresh_row(i)
|
|
2022
|
|
2023
|
|
2024 class attack_panel(wx.Panel):
|
|
2025 def __init__(self, parent, handler):
|
|
2026 pname = handler.xml.set("name", 'Melee')
|
|
2027 wx.Panel.__init__(self, parent, -1)
|
|
2028
|
|
2029 self.a_grid = attack_grid(self, handler)
|
|
2030 self.w_panel = weapon_panel(self, handler)
|
|
2031 self.sizer = wx.BoxSizer(wx.VERTICAL)
|
|
2032 self.sizer.Add(self.a_grid, 1, wx.EXPAND)
|
|
2033 self.sizer.Add(self.w_panel, 2, wx.EXPAND)
|
|
2034 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
2035 self.SetSizer(self.sizer)
|
|
2036
|
|
2037 def on_size(self,event):
|
|
2038 s = self.GetClientSizeTuple()
|
|
2039 self.sizer.SetDimension(0,0,s[0],s[1])
|
|
2040
|
|
2041 def refresh_data(self):
|
|
2042 self.w_panel.refresh_data()
|
|
2043 self.a_grid.refresh_data()
|
|
2044
|
|
2045
|
|
2046 class ac_panel(wx.Panel):
|
|
2047 def __init__(self, parent, handler):
|
|
2048 pname = handler.xml.set("name", 'Armor')
|
|
2049 wx.Panel.__init__(self, parent, -1)
|
|
2050 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
2051 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
2052 sizer.Add(wx.Button(self, 10, "Remove Armor"), 1, wx.EXPAND)
|
|
2053 sizer.Add(wx.Size(10,10))
|
|
2054 sizer.Add(wx.Button(self, 20, "Add Armor"), 1, wx.EXPAND)
|
|
2055 self.sizer = sizer
|
|
2056 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
2057 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
2058 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
2059 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
2060 self.xml = handler.xml
|
|
2061 n_list = handler.xml[:]
|
|
2062 self.n_list = n_list
|
|
2063 col_names = ['Armor','bonus','maxdex','cp','sf','weight','speed','type']
|
|
2064 self.grid.CreateGrid(len(n_list),len(col_names),1)
|
|
2065 self.grid.SetRowLabelSize(0)
|
|
2066 for i in range(len(col_names)): self.grid.SetColLabelValue(i,col_names[i])
|
|
2067 self.atts =['name','bonus','maxdex','checkpenalty','spellfailure','weight','speed','type']
|
|
2068 for i in range(len(n_list)): self.refresh_row(i)
|
|
2069 self.temp_dom = None
|
|
2070 self.SetSizer(self.sizer)
|
|
2071
|
|
2072 def on_cell_change(self,evt):
|
|
2073 row = evt.GetRow()
|
|
2074 col = evt.GetCol()
|
|
2075 value = self.grid.GetCellValue(row,col)
|
|
2076 if col >= 1 and col <= 5:
|
|
2077 try:
|
|
2078 int(value)
|
|
2079 self.n_list[row].set(self.atts[col],value)
|
|
2080 except: self.grid.SetCellValue(row,col,"0")
|
|
2081 else: self.n_list[row].set(self.atts[col],value)
|
|
2082
|
|
2083 def refresh_row(self,i):
|
|
2084 n = self.n_list[i]
|
|
2085 for y in range(len(self.atts)):
|
|
2086 self.grid.SetCellValue(i,y,n.get(self.atts[y]))
|
|
2087
|
|
2088 def on_remove(self,evt):
|
|
2089 rows = self.grid.GetNumberRows()
|
|
2090 for i in range(rows):
|
|
2091 if self.grid.IsInSelection(i,0):
|
|
2092 self.grid.DeleteRows(i)
|
|
2093 self.xml.remove(self.n_list[i])
|
|
2094
|
|
2095 def on_add(self,evt):
|
|
2096 if not self.temp_dom:
|
|
2097 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20armor.xml")
|
|
2098 self.temp_dom = tree.getroot()
|
|
2099 f_list = self.temp_dom.findall('armor')
|
|
2100 opts = []
|
|
2101 for f in f_list: opts.append(f.get('name'))
|
|
2102 dlg = wx.SingleChoiceDialog(self,'Choose Armor:','Armor List',opts)
|
|
2103 if dlg.ShowModal() == wx.ID_OK:
|
|
2104 i = dlg.GetSelection()
|
|
2105 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
2106 self.grid.AppendRows(1)
|
|
2107 self.n_list = self.xml.findall('armor')
|
|
2108 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
2109 dlg.Destroy()
|
|
2110
|
|
2111 def on_size(self,event):
|
|
2112 s = self.GetClientSizeTuple()
|
|
2113 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
2114 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
2115 (w,h) = self.grid.GetClientSizeTuple()
|
|
2116 cols = self.grid.GetNumberCols()
|
|
2117 col_w = w/(cols+2)
|
|
2118 self.grid.SetColSize(0,col_w*3)
|
|
2119 for i in range(1,cols): self.grid.SetColSize(i,col_w)
|
|
2120
|
|
2121
|
|
2122 class class_panel(wx.Panel):
|
|
2123 def __init__(self, parent, handler):
|
|
2124 pname = handler.xml.set("name", 'Class')
|
|
2125 wx.Panel.__init__(self, parent, -1)
|
|
2126 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
2127 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
2128 sizer.Add(wx.Button(self, 10, "Remove Class"), 1, wx.EXPAND)
|
|
2129 sizer.Add(wx.Size(10,10))
|
|
2130 sizer.Add(wx.Button(self, 20, "Add Class"), 1, wx.EXPAND)
|
|
2131 self.sizer = sizer
|
|
2132 self.SetSizer(self.sizer)
|
|
2133 self.Bind(wx.EVT_SIZE, self.on_size)
|
|
2134 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10)
|
|
2135 self.Bind(wx.EVT_BUTTON, self.on_add, id=20)
|
|
2136 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
2137
|
|
2138 n_list = handler.xml[:]
|
|
2139 self.n_list = n_list
|
|
2140 self.xml = handler.xml
|
|
2141 self.grid.CreateGrid(len(n_list),2,1)
|
|
2142 self.grid.SetRowLabelSize(0)
|
|
2143 self.grid.SetColLabelValue(0,"Class")
|
|
2144 self.grid.SetColLabelValue(1,"Level")
|
|
2145 for i in range(len(n_list)): self.refresh_row(i)
|
|
2146 self.temp_dom = None
|
|
2147
|
|
2148 def on_cell_change(self,evt):
|
|
2149 row = evt.GetRow()
|
|
2150 col = evt.GetCol()
|
|
2151 value = self.grid.GetCellValue(row,col)
|
|
2152 try:
|
|
2153 int(value)
|
|
2154 self.n_list[row].set('level',value)
|
|
2155 except: self.grid.SetCellValue(row,col,"1")
|
|
2156
|
|
2157 def refresh_row(self,i):
|
|
2158 n = self.n_list[i]
|
|
2159 name = n.get('name')
|
|
2160 level = n.get('level')
|
|
2161 self.grid.SetCellValue(i,0,name)
|
|
2162 self.grid.SetReadOnly(i,0)
|
|
2163 self.grid.SetCellValue(i,1,level)
|
|
2164
|
|
2165 def on_remove(self,evt):
|
|
2166 rows = self.grid.GetNumberRows()
|
|
2167 for i in range(rows):
|
|
2168 if self.grid.IsInSelection(i,0):
|
|
2169 self.grid.DeleteRows(i)
|
|
2170 self.xml.remove(self.n_list[i])
|
|
2171
|
|
2172 def on_add(self,evt):
|
|
2173 if not self.temp_dom:
|
|
2174 tree = parse(orpg.dirpath.dir_struct["d20"]+"d20classes.xml")
|
|
2175 self.temp_dom = tree.getroot()
|
|
2176 f_list = self.temp_dom.findall('class')
|
|
2177 opts = []
|
|
2178 for f in f_list: opts.append(f.get('name'))
|
|
2179 dlg = wx.SingleChoiceDialog(self,'Choose Class','Classes',opts)
|
|
2180 if dlg.ShowModal() == wx.ID_OK:
|
|
2181 i = dlg.GetSelection()
|
|
2182 new_node = self.xml.append(XML(tostring(f_list[i])))
|
|
2183 self.grid.AppendRows(1)
|
|
2184 self.n_list = self.xml.findall('class')
|
|
2185 self.refresh_row(self.grid.GetNumberRows()-1)
|
|
2186 dlg.Destroy()
|
|
2187
|
|
2188 def on_size(self,event):
|
|
2189 s = self.GetClientSizeTuple()
|
|
2190 self.grid.SetDimensions(0,0,s[0],s[1]-25)
|
|
2191 self.sizer.SetDimension(0,s[1]-25,s[0],25)
|
|
2192 (w,h) = self.grid.GetClientSizeTuple()
|
|
2193 cols = self.grid.GetNumberCols()
|
|
2194 col_w = w/(cols)
|
|
2195 for i in range(0,cols): self.grid.SetColSize(i,col_w)
|