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