Mercurial > traipse_dev
annotate orpg/gametree/nodehandlers/dnd35.py @ 227:81d0bfd5e800 alpha
Traipse Alpha 'OpenRPG' {100612-00}
Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for
developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to
the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user.
Update Summary (Preparing to close updates)
New Features:
New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order
Fixes:
Fix to InterParse that was causing an Infernal Loop with Namespace Internal
Fix to XML data, removed old Minidom and switched to Element Tree
Fix to Server that was causing eternal attempt to find a Server ID, in Register Rooms thread
Fix to metaservers.xml file not being created
author | sirebral |
---|---|
date | Sat, 12 Jun 2010 03:50:37 -0500 |
parents | bf799efe7a8a |
children | 3bbfd84619c0 |
rev | line source |
---|---|
155 | 1 from core import * |
2 from containers import * | |
3 from string import * #a 1.6003 | |
82
2fa8bd6785a5
TerminalWriter's colors are nice, but if no debug console is open it causes the software to look for one until a recursion error is created. Crash reports are sent to the debug console and a pop-up tells the user one has happened. Fix to chat window from SnowDog.
sirebral
parents:
71
diff
changeset
|
4 from inspect import * #a 1.9001 |
2fa8bd6785a5
TerminalWriter's colors are nice, but if no debug console is open it causes the software to look for one until a recursion error is created. Crash reports are sent to the debug console and a pop-up tells the user one has happened. Fix to chat window from SnowDog.
sirebral
parents:
71
diff
changeset
|
5 from orpg.dirpath import dir_struct |
124 | 6 from xml.etree.ElementTree import parse |
155 | 7 dnd35_EXPORT = wx.NewId() |
8 | |
9 ############Global Stuff############## | |
10 | |
11 HP_CUR = wx.NewId() | |
12 HP_MAX = wx.NewId() | |
13 | |
14 def getRoot (node): # a 1.5002 this whole function is new. | |
15 root = None | |
16 target = node | |
17 while target != None: | |
18 root = target | |
19 target = target.hparent | |
20 return root | |
21 | |
22 #a 1.6 convinience function added safeGetAttr | |
23 def safeGetAttr(node, label, defRetV=None): | |
24 cna=node.attrib | |
124 | 25 for key in cna: |
155 | 26 if key == label: return cna[key] |
27 return defRetV | |
28 #a 1.6... safeGetAttr end. | |
29 | |
30 ########End of My global Stuff######## | |
31 ########Start of Main Node Handlers####### | |
32 class dnd35char_handler(container_handler): | |
33 """ Node handler for a dnd35 charactor | |
34 <nodehandler name='?' module='dnd35' class='dnd35char_handler2' /> | |
35 """ | |
36 def __init__(self,xml_dom,tree_node): | |
37 node_handler.__init__(self,xml_dom,tree_node) | |
38 self.Version = "v1.000" #a 1.6000 general documentation, usage. | |
39 print "dnd35char_handler - version:",self.Version #m 1.6000 | |
40 self.hparent = None #a 1.5002 allow ability to run up tree, this is the | |
41 self.frame = component.get('frame') | |
42 self.child_handlers = {} | |
43 self.new_child_handler('general','GeneralInformation',dnd35general,'gear') | |
44 self.new_child_handler('inventory','MoneyAndInventory',dnd35inventory,'money') | |
45 self.new_child_handler('character','ClassesAndStats',dnd35classnstats,'knight') | |
46 self.new_child_handler('snf','SkillsAndFeats',dnd35skillsnfeats,'book') | |
47 self.new_child_handler('combat','Combat',dnd35combat,'spears') | |
48 self.myeditor = None | |
49 | |
50 def new_child_handler(self,tag,text,handler_class,icon='gear'): | |
51 node_list = self.xml.findall(tag) | |
52 tree = self.tree | |
53 i = self.tree.icons[icon] | |
54 new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) | |
55 handler = handler_class(node_list[0],new_tree_node,self) | |
56 tree.SetPyData(new_tree_node,handler) | |
57 self.child_handlers[tag] = handler | |
58 | |
59 def get_design_panel(self,parent): | |
60 return tabbed_panel(parent,self,1) | |
61 | |
62 def get_use_panel(self,parent): | |
63 return tabbed_panel(parent,self,2) | |
64 | |
65 def tohtml(self): | |
66 html_str = "<table><tr><td colspan=2 >" | |
67 html_str += self.general.tohtml()+"</td></tr>" | |
68 html_str += "<tr><td width='50%' valign=top >"+self.abilities.tohtml() | |
69 html_str += "<P>" + self.saves.tohtml() | |
70 html_str += "<P>" + self.attacks.tohtml() | |
71 html_str += "<P>" + self.ac.tohtml() | |
72 html_str += "<P>" + self.feats.tohtml() | |
73 html_str += "<P>" + self.inventory.tohtml() +"</td>" | |
74 html_str += "<td width='50%' valign=top >"+self.classes.tohtml() | |
75 html_str += "<P>" + self.hp.tohtml() | |
76 html_str += "<P>" + self.skills.tohtml() +"</td>" | |
77 html_str += "</tr></table>" | |
78 return html_str | |
79 | |
80 def about(self): | |
81 """html_str = "<img src='" + dir_struct["icon"] | |
82 html_str += "dnd3e_logo.gif' ><br /><b>dnd35 Character Tool " | |
83 html_str += self.Version+"</b>" #m 1.6000 was hard coded. | |
84 html_str += "<br />by Dj Gilcrease<br />digitalxero@gmail.com" | |
151 | 85 return html_str""" |
86 text = 'dnd35 Character Tool' + self.Version +'\n' | |
87 text += 'by Dj Gilcrease digitalxero@gmail.com' | |
155 | 88 return text |
89 | |
90 ########Core Handlers are done now############ | |
91 ########Onto the Sub Nodes######## | |
92 ##Primary Sub Node## | |
93 | |
94 class outline_panel(wx.Panel): | |
95 def __init__(self, parent, handler, wnd, txt,): | |
96 self.parent = parent #a 1.9001 | |
97 wx.Panel.__init__(self, parent, -1) | |
98 self.panel = wnd(self,handler) | |
99 self.sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,txt), wx.VERTICAL) | |
100 | |
101 self.sizer.Add(self.panel, 1, wx.EXPAND) | |
102 self.SetSizer(self.sizer) | |
103 self.SetAutoLayout(True) | |
104 self.Fit() | |
105 | |
106 class dnd35_char_child(node_handler): | |
107 """ Node Handler for skill. This handler will be | |
108 created by dnd35char_handler. | |
109 """ | |
110 def __init__(self,xml_dom,tree_node,parent): | |
111 node_handler.__init__(self,xml_dom,tree_node) | |
112 self.char_hander = parent | |
113 self.drag = False | |
114 self.frame = component.get('frame') | |
115 self.myeditor = None | |
116 | |
117 def on_drop(self,evt): | |
118 pass | |
119 | |
120 def on_rclick(self,evt): | |
121 pass | |
122 | |
123 def on_ldclick(self,evt): | |
124 return | |
125 | |
126 def on_html(self,evt): | |
127 html_str = self.tohtml() | |
128 wnd = http_html_window(self.frame.note,-1) | |
129 wnd.title = self.xml.get('name') | |
130 self.frame.add_panel(wnd) | |
131 wnd.SetPage(html_str) | |
132 | |
133 def get_design_panel(self,parent): | |
134 pass | |
135 | |
136 def get_use_panel(self,parent): | |
137 return self.get_design_panel(parent) | |
138 | |
139 def delete(self): | |
140 pass | |
141 | |
142 class dnd35general(dnd35_char_child): | |
143 """ Node Handler for general information. This handler will be | |
144 created by dnd35char_handler. | |
145 """ | |
146 def __init__(self,xml_dom,tree_node,parent): | |
147 dnd35_char_child.__init__(self,xml_dom,tree_node,parent) | |
148 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
149 self.root = getRoot(self) #a 1.5002 | |
150 self.root.general = self #a 1.5002 | |
151 self.charName = self.get_char_name() # a 1.5002 make getting name easier. | |
152 | |
153 def get_design_panel(self,parent): | |
154 wnd = outline_panel(parent,self,gen_grid,"General Information") | |
155 wnd.title = "General Info" | |
156 return wnd | |
157 | |
158 def tohtml(self): | |
159 n_list = self.xml.getchildren() | |
160 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>" | |
161 for n in n_list: | |
162 html_str += "<B>"+n.tag.capitalize() +":</B> " | |
163 html_str += n.text + ", " | |
164 html_str = html_str[:len(html_str)-2] + "</td></tr></table>" | |
165 return html_str | |
166 | |
167 def on_name_change(self,name): | |
168 self.char_hander.rename(name) | |
169 #o 1.5002 self.char_hander = parent in this case. | |
170 self.charName = name #a 1.5002 make getting name easier. | |
171 | |
172 def get_char_name( self ): | |
173 node = self.xml.findall( 'name' )[0] | |
174 return node.text | |
175 | |
176 class gen_grid(wx.grid.Grid): | |
177 """grid for gen info""" | |
178 def __init__(self, parent, handler): | |
179 pname = handler.xml.set("name", 'General') | |
180 self.hparent = handler #a 1.5002 allow ability to run up tree, needed | |
181 # a 1.5002 parent is functional parent, not invoking parent. | |
182 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
183 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
184 self.handler = handler | |
185 n_list = handler.xml.getchildren() | |
186 self.CreateGrid(len(n_list),2) | |
187 self.SetRowLabelSize(0) | |
188 self.SetColLabelSize(0) | |
189 self.n_list = n_list | |
190 i = 0 | |
191 for i in range(len(n_list)): self.refresh_row(i) | |
192 | |
193 def on_cell_change(self,evt): | |
194 row = evt.GetRow() | |
195 col = evt.GetCol() | |
196 value = self.GetCellValue(row,col) | |
197 t_node = self.n_list[row] | |
198 t_node.text = value | |
199 if row==0: self.handler.on_name_change(value) | |
200 | |
201 def refresh_row(self, rowi): | |
202 self.SetCellValue(rowi, 0, self.n_list[rowi].tag) | |
203 self.SetReadOnly(rowi, 0) | |
204 self.SetCellValue(rowi, 1, self.n_list[rowi].text) | |
205 self.AutoSizeColumn(1) | |
206 | |
207 class dnd35inventory(dnd35_char_child): | |
208 """ Node Handler for general information. This handler will be | |
209 created by dnd35char_handler. | |
210 """ | |
211 def __init__(self,xml_dom,tree_node,parent): | |
212 dnd35_char_child.__init__(self,xml_dom,tree_node,parent) | |
213 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
214 self.root = getRoot(self) #a 1.6009 | |
215 self.root.inventory = self #a 1.6009 | |
216 | |
217 def get_design_panel(self,parent): | |
218 wnd = inventory_pane(parent, self) #outline_panel(parent,self,inventory_grid,"Inventory") | |
219 wnd.title = "Inventory" | |
220 return wnd | |
221 | |
222 def tohtml(self): | |
223 n_list = self.xml.getchildren() | |
224 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Inventory</th></tr><tr><td>" | |
225 for n in n_list: | |
226 html_str += "<B>"+n.tag.capitalize() +":</B> " | |
227 html_str += n.text + "<br />" | |
228 html_str = html_str[:len(html_str)-2] + "</td></tr></table>" | |
229 return html_str | |
230 | |
231 class inventory_pane(wx.Panel): | |
232 def __init__(self, parent, handler): | |
233 wx.Panel.__init__(self, parent, wx.ID_ANY) | |
234 self.n_list = handler.xml.getchildren() | |
235 self.autosize = False | |
236 self.sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Inventory"), wx.VERTICAL) | |
237 self.lang = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Languages") | |
238 self.gear = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Gear") | |
239 self.magic = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_BESTWRAP, name="Magic") | |
240 self.grid = wx.grid.Grid(self, wx.ID_ANY, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
241 self.grid.CreateGrid(len(self.n_list)-3,2) | |
242 self.grid.SetRowLabelSize(0) | |
243 self.grid.SetColLabelSize(0) | |
244 for i in xrange(len(self.n_list)): self.refresh_row(i) | |
245 sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
246 sizer1.Add(self.grid, 1, wx.EXPAND) | |
247 sizer1.Add(self.lang, 1, wx.EXPAND) | |
248 self.sizer.Add(sizer1, 0, wx.EXPAND) | |
249 sizer2 = wx.BoxSizer(wx.HORIZONTAL) | |
250 sizer2.Add(self.gear, 1, wx.EXPAND) | |
251 sizer2.Add(self.magic, 1, wx.EXPAND) | |
252 self.sizer.Add(sizer2, 1, wx.EXPAND) | |
253 self.SetSizer(self.sizer) | |
254 self.SetAutoLayout(True) | |
255 self.Fit() | |
256 self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.lang) | |
257 self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.gear) | |
258 self.Bind(wx.EVT_TEXT, self.onTextNodeChange, self.magic) | |
259 self.Bind(wx.grid.EVT_GRID_EDITOR_HIDDEN, self.on_cell_change, self.grid) | |
260 | |
261 def fillTextNode(self, name, value): | |
262 if name == 'Languages': self.lang.SetValue(value) | |
263 elif name == 'Gear': self.gear.SetValue(value) | |
264 elif name == 'Magic': self.magic.SetValue(value) | |
265 | |
266 def onTextNodeChange(self, event): | |
267 id = event.GetId() | |
268 if id == self.gear.GetId(): | |
269 nodeName = 'Gear' | |
270 value = self.gear.GetValue() | |
271 elif id == self.magic.GetId(): | |
272 nodeName = 'Magic' | |
273 value = self.magic.GetValue() | |
274 elif id == self.lang.GetId(): | |
275 nodeName = 'Languages' | |
276 value = self.lang.GetValue() | |
277 for node in self.n_list: | |
278 if node._get_tagName() == nodeName: node.text = value | |
279 | |
280 def saveMoney(self, row, col): | |
281 value = self.grid.GetCellValue(row, col) | |
282 self.n_list[row].text = value | |
283 | |
284 def on_cell_change(self, evt): | |
285 row = evt.GetRow() | |
286 col = evt.GetCol() | |
287 self.grid.AutoSizeColumn(col) | |
288 wx.CallAfter(self.saveMoney, row, col) | |
289 | |
290 def refresh_row(self, row): | |
291 tagname = self.n_list[row].tag | |
292 value = self.n_list[row].text | |
293 if tagname == 'Gear': self.fillTextNode(tagname, value) | |
294 elif tagname == 'Magic': self.fillTextNode(tagname, value) | |
295 elif tagname == 'Languages': self.fillTextNode(tagname, value) | |
296 else: | |
297 self.grid.SetCellValue(row, 0, tagname) | |
298 self.grid.SetReadOnly(row, 0) | |
299 self.grid.SetCellValue(row, 1, value) | |
300 self.grid.AutoSize() | |
301 | |
302 | |
303 class dnd35classnstats(dnd35_char_child): | |
304 """ Node handler for a dnd35 charactor | |
305 <nodehandler name='?' module='dnd35' class='dnd35char_handler2' /> | |
306 """ | |
307 def __init__(self,xml_dom,tree_node,parent): | |
308 node_handler.__init__(self,xml_dom,tree_node) | |
309 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
310 dnd35_char_child.__init__(self,xml_dom,tree_node,parent) | |
311 self.frame = component.get('frame') | |
312 self.child_handlers = {} | |
313 self.new_child_handler('abilities','Abilities Scores',dnd35ability,'gear') | |
314 self.new_child_handler('classes','Classes',dnd35classes,'knight') | |
315 self.new_child_handler('saves','Saves',dnd35saves,'skull') | |
316 self.myeditor = None | |
317 | |
318 def new_child_handler(self,tag,text,handler_class,icon='gear'): | |
319 node_list = self.xml.findall(tag) | |
320 tree = self.tree | |
321 i = self.tree.icons[icon] | |
322 new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) | |
323 handler = handler_class(node_list[0],new_tree_node,self) | |
324 tree.SetPyData(new_tree_node,handler) | |
325 self.child_handlers[tag] = handler | |
326 | |
327 def get_design_panel(self,parent): | |
328 return tabbed_panel(parent,self,1) | |
329 | |
330 def get_use_panel(self,parent): | |
331 return tabbed_panel(parent,self,2) | |
332 | |
333 class class_char_child(node_handler): | |
334 """ Node Handler for skill. This handler will be | |
335 created by dnd35char_handler. | |
336 """ | |
337 def __init__(self,xml_dom,tree_node,parent): | |
338 node_handler.__init__(self,xml_dom,tree_node) | |
339 self.char_hander = parent | |
340 self.drag = False | |
341 self.frame = component.get('frame') | |
342 self.myeditor = None | |
343 | |
344 def on_drop(self,evt): | |
345 pass | |
346 | |
347 def on_rclick(self,evt): | |
348 pass | |
349 | |
350 def on_ldclick(self,evt): | |
351 return | |
352 | |
353 def on_html(self,evt): | |
354 html_str = self.tohtml() | |
355 wnd = http_html_window(self.frame.note,-1) | |
356 wnd.title = self.xml.get('name') | |
357 self.frame.add_panel(wnd) | |
358 wnd.SetPage(html_str) | |
359 | |
360 def get_design_panel(self,parent): | |
361 pass | |
362 | |
363 def get_use_panel(self,parent): | |
364 return self.get_design_panel(parent) | |
365 | |
366 def delete(self): | |
367 pass | |
368 | |
369 class dnd35ability(class_char_child): | |
370 """ Node Handler for ability. This handler will be | |
371 created by dnd35char_handler. | |
372 """ | |
373 def __init__(self,xml_dom,tree_node,parent): | |
374 class_char_child.__init__(self,xml_dom,tree_node,parent) | |
375 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
376 self.root = getRoot(self) #a 1.5002 get top of our local function tree. | |
377 self.root.abilities = self #a 1.5002 let other classes find me. | |
378 | |
379 self.abilities = {} | |
380 node_list = self.xml.findall('stat') | |
381 tree = self.tree | |
382 icons = tree.icons | |
383 | |
384 for n in node_list: | |
385 name = n.get('abbr') | |
386 self.abilities[name] = n | |
387 new_tree_node = tree.AppendItem( self.mytree_node, name, icons['gear'], icons['gear'] ) | |
388 tree.SetPyData( new_tree_node, self ) | |
389 | |
390 def on_rclick( self, evt ): | |
391 item = self.tree.GetSelection() | |
392 name = self.tree.GetItemText( item ) | |
393 if not item == self.mytree_node: #a 1.6016 | |
394 mod = self.get_mod( name ) | |
395 if mod >= 0: mod1 = "+" | |
396 else: mod1 = "" | |
397 chat = self.chat | |
398 txt = '%s check: [1d20%s%s]' % ( name, mod1, mod ) | |
399 chat.ParsePost( txt, True, True ) | |
400 | |
401 def get_mod(self,abbr): | |
402 score = int(self.abilities[abbr].get('base')) | |
403 mod = (score - 10) / 2 | |
404 mod = int(mod) | |
405 return mod | |
406 | |
407 def set_score(self,abbr,score): | |
408 if score >= 0: self.abilities[abbr].set("base",str(score)) | |
409 | |
410 def get_design_panel(self,parent): | |
411 wnd = outline_panel(parent,self,abil_grid,"Abilities") | |
412 wnd.title = "Abilities (edit)" | |
413 return wnd | |
414 | |
415 def tohtml(self): | |
416 html_str = """<table border='1' width=100%><tr BGCOLOR=#E9E9E9 ><th width='50%'>Ability</th> | |
417 <th>Base</th><th>Modifier</th></tr>""" | |
418 node_list = self.xml.findall('stat') | |
419 for n in node_list: | |
420 name = n.get('name') | |
421 abbr = n.get('abbr') | |
422 base = n.get('base') | |
423 mod = str(self.get_mod(abbr)) | |
424 if int(mod) >= 0: mod1 = "+" | |
425 else: mod1 = "" | |
426 html_str = (html_str + "<tr ALIGN='center'><td>"+ | |
427 name+"</td><td>"+base+'</td><td>%s%s</td></tr>' % (mod1, mod)) | |
428 html_str = html_str + "</table>" | |
429 return html_str | |
430 | |
431 class abil_grid(wx.grid.Grid): | |
432 """grid for abilities""" | |
433 def __init__(self, parent, handler): | |
434 pname = handler.xml.set("name", 'Stats') | |
435 self.hparent = handler #a 1.5002 allow ability to run up tree. | |
436 self.root = getRoot(self) | |
437 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
438 self.Bind(wx.EVT_SIZE, self.on_size) | |
439 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
440 self.handler = handler | |
441 stats = handler.xml.findall('stat') | |
442 self.CreateGrid(len(stats),3) | |
443 self.SetRowLabelSize(0) | |
444 col_names = ['Ability','Score','Modifier'] | |
445 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i]) | |
446 self.stats = stats | |
447 i = 0 | |
448 for i in range(len(stats)): self.refresh_row(i) | |
449 self.char_wnd = None | |
450 | |
451 def on_cell_change(self,evt): | |
452 row = evt.GetRow() | |
453 col = evt.GetCol() | |
454 value = self.GetCellValue(row,col) | |
455 try: | |
456 int(value) | |
457 self.stats[row].set('base',value) | |
458 self.refresh_row(row) | |
459 except: | |
460 self.SetCellValue(row,col,"0") | |
461 if self.char_wnd: self.char_wnd.refresh_data() | |
462 | |
463 def refresh_row(self,rowi): | |
464 s = self.stats[rowi] | |
465 name = s.get('name') | |
466 abbr = s.get('abbr') | |
467 self.SetCellValue(rowi,0,name) | |
468 self.SetReadOnly(rowi,0) | |
469 self.SetCellValue(rowi,1,s.get('base')) | |
470 self.SetCellValue(rowi,2,str(self.handler.get_mod(abbr))) | |
471 self.SetReadOnly(rowi,2) | |
472 self.root.saves.refresh_data() #a 1.9002 | |
473 self.root.attacks.refreshMRdata() #a 1.9001 ` | |
474 | |
475 def on_size(self,evt): | |
476 (w,h) = self.GetClientSizeTuple() | |
477 cols = self.GetNumberCols() | |
478 col_w = w/(cols+2) | |
479 self.SetColSize(0,col_w*3) | |
480 for i in range(1,cols): self.SetColSize(i,col_w) | |
481 evt.Skip() | |
482 self.Refresh() | |
483 | |
484 def refresh_data(self): | |
485 for r in range(self.GetNumberRows()-1): self.refresh_row(r) | |
486 | |
487 class dnd35classes(class_char_child): | |
488 """ Node Handler for classes. This handler will be | |
489 created by dnd35char_handler. | |
490 """ | |
491 def __init__(self,xml_dom,tree_node,parent): | |
492 class_char_child.__init__(self,xml_dom,tree_node,parent) | |
493 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
494 self.root = getRoot(self) | |
495 self.root.classes = self | |
496 | |
497 def get_design_panel(self,parent): | |
498 wnd = outline_panel(parent,self,class_panel,"Classes") | |
499 wnd.title = "Classes" | |
500 return wnd | |
501 | |
502 def tohtml(self): | |
503 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Classes</th></tr><tr><td>" | |
504 n_list = self.xml.getchildren() | |
505 for n in n_list: html_str += n.get('name') + " ("+n.get('level')+"), " | |
506 html_str = html_str[:len(html_str)-2] + "</td></tr></table>" | |
507 return html_str | |
508 | |
509 def get_char_lvl( self, attr ): | |
510 node_list = self.xml.findall('class') | |
511 tot = 0 #a 1.5009 actually, slipping in a quick enhancement ;-) | |
512 for n in node_list: | |
513 lvl = n.get('level') | |
514 tot += int(lvl) | |
515 type = n.get('name') | |
516 if attr == "level": return lvl | |
517 elif attr == "class": return type | |
518 if attr == "lvl": return tot | |
519 | |
520 def get_class_lvl( self, classN ): | |
521 node_list = self.xml.findall('class') | |
522 for n in node_list: | |
523 lvl = n.get('level') | |
524 type = n.get('name') | |
525 if classN == type: return lvl | |
526 | |
527 class class_panel(wx.Panel): | |
528 def __init__(self, parent, handler): | |
529 pname = handler.xml.set("name", 'Class') | |
530 wx.Panel.__init__(self, parent, -1) | |
531 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
532 sizer = wx.BoxSizer(wx.VERTICAL) | |
533 sizer.Add(self.grid, 1, wx.EXPAND) | |
534 | |
535 sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
536 sizer1.Add(wx.Button(self, 10, "Remove Class"), 0, wx.EXPAND) | |
537 sizer1.Add(wx.Size(10,10)) | |
538 sizer1.Add(wx.Button(self, 20, "Add Class"), 0, wx.EXPAND) | |
539 | |
540 sizer.Add(sizer1, 0, wx.EXPAND) | |
541 self.sizer = sizer | |
542 self.SetSizer(self.sizer) | |
543 self.SetAutoLayout(True) | |
544 self.Fit() | |
545 | |
546 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) | |
547 self.Bind(wx.EVT_BUTTON, self.on_add, id=20) | |
548 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
549 | |
550 n_list = handler.xml.getchildren() | |
551 self.n_list = n_list | |
552 self.xml = handler.xml | |
553 self.grid.CreateGrid(len(n_list),3,1) | |
554 self.grid.SetRowLabelSize(0) | |
555 self.grid.SetColLabelValue(0,"Class") | |
556 self.grid.SetColLabelValue(1,"Level") | |
557 self.grid.SetColLabelValue(2,"Refrence") | |
558 for i in range(len(n_list)): self.refresh_row(i) | |
559 self.temp_dom = None | |
560 | |
561 def on_cell_change(self,evt): | |
562 row = evt.GetRow() | |
563 col = evt.GetCol() | |
564 value = self.grid.GetCellValue(row,col) | |
565 try: | |
566 int(value) | |
567 self.n_list[row].set('level',value) | |
568 except: self.grid.SetCellValue(row,col,"1") | |
569 | |
570 | |
571 def refresh_row(self,i): | |
572 n = self.n_list[i] | |
573 name = n.get('name') | |
574 level = n.get('level') | |
575 book = n.get('book') | |
576 self.grid.SetCellValue(i,0,name) | |
577 self.grid.SetReadOnly(i,0) | |
578 self.grid.SetCellValue(i,1,level) | |
579 self.grid.SetCellValue(i,2,book) | |
580 self.grid.SetReadOnly(i,0) | |
581 self.grid.AutoSizeColumn(0) | |
582 self.grid.AutoSizeColumn(1) | |
583 self.grid.AutoSizeColumn(2) | |
584 | |
585 def on_remove(self,evt): | |
586 rows = self.grid.GetNumberRows() | |
587 for i in range(rows): | |
588 if self.grid.IsInSelection(i,0): | |
589 self.grid.DeleteRows(i) | |
590 self.xml.remove(self.n_list[i]) | |
591 | |
592 def on_add(self,evt): | |
593 if not self.temp_dom: | |
594 tree = parse(dir_struct["dnd35"]+"dnd35classes.xml") | |
595 xml_dom = tree.getroot() | |
596 self.temp_dom = xml_dom | |
597 f_list = self.temp_dom.findall('class') | |
598 opts = [] | |
599 for f in f_list: opts.append(f.get('name')) | |
600 dlg = wx.SingleChoiceDialog(self,'Choose Class','Classes',opts) | |
601 if dlg.ShowModal() == wx.ID_OK: | |
602 i = dlg.GetSelection() | |
603 new_node = self.xml.append(f_list[i]) | |
604 self.grid.AppendRows(1) | |
605 self.refresh_row(self.grid.GetNumberRows()-1) | |
606 dlg.Destroy() | |
151 | 607 |
155 | 608 def on_size(self,event): |
609 s = self.GetClientSizeTuple() | |
610 self.grid.SetDimensions(0,0,s[0],s[1]-25) | |
611 self.sizer.SetDimension(0,s[1]-25,s[0],25) | |
612 (w,h) = self.grid.GetClientSizeTuple() | |
613 cols = self.grid.GetNumberCols() | |
614 col_w = w/(cols) | |
615 for i in range(0,cols): self.grid.SetColSize(i,col_w) | |
616 | |
617 | |
618 class dnd35saves(class_char_child): | |
619 """ Node Handler for saves. This handler will be | |
620 created by dnd35char_handler. | |
621 """ | |
622 def __init__(self,xml_dom,tree_node,parent): | |
623 class_char_child.__init__(self,xml_dom,tree_node,parent) | |
624 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
625 self.saveGridFrame = [] #a 1.9002 handle list, check frame for close. | |
626 | |
627 tree = self.tree | |
628 icons = self.tree.icons | |
629 | |
630 self.root = getRoot(self) #a 1.5002 | |
631 self.root.saves = self #a 1.6009 | |
632 node_list = self.xml.findall('save') | |
633 self.saves={} | |
634 for n in node_list: | |
635 name = n.get('name') | |
636 self.saves[name] = n | |
637 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear']) | |
638 tree.SetPyData(new_tree_node,self) | |
639 | |
640 #a 1.9002 this whole method | |
641 def refresh_data(self): # refresh the data in the melee/ranged section | |
642 # of the attack chart. | |
643 # count backwards, maintains context despite "removes" | |
644 for i in range(len(self.saveGridFrame)-1,-1,-1): | |
645 x = self.saveGridFrame[i] | |
646 if x == None: x.refresh_data() | |
647 else: self.saveGridFrame.remove(x) | |
648 | |
649 def get_mod(self,name): | |
650 save = self.saves[name] | |
651 stat = save.get('stat') | |
652 stat_mod = self.root.abilities.get_mod(stat) | |
653 base = int(save.get('base')) | |
654 miscmod = int(save.get('miscmod')) | |
655 magmod = int(save.get('magmod')) | |
656 total = stat_mod + base + miscmod + magmod | |
657 return total | |
658 | |
659 def on_rclick(self,evt): | |
660 | |
661 item = self.tree.GetSelection() | |
662 name = self.tree.GetItemText(item) | |
663 if item == self.mytree_node: | |
664 pass #a 1.5003 syntatic place holder | |
665 return #a 1.5003 | |
666 else: | |
667 mod = self.get_mod(name) | |
668 if mod >= 0: mod1 = "+" | |
669 else: mod1 = "" | |
670 chat = self.chat | |
671 txt = '%s save: [1d20%s%s]' % (name, mod1, mod) | |
672 chat.ParsePost( txt, True, True ) | |
673 | |
674 def get_design_panel(self,parent): | |
675 wnd = outline_panel(parent,self,save_grid,"Saves") | |
676 wnd.title = "Saves" | |
677 return wnd | |
678 | |
679 def tohtml(self): | |
680 html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > | |
681 <th width='30%'>Save</th> | |
682 <th>Key</th><th>Base</th><th>Abil</th><th>Magic</th> | |
683 <th>Misc</th><th>Total</th></tr>""" | |
684 node_list = self.xml.findall('save') | |
685 for n in node_list: | |
686 name = n.get('name') | |
687 stat = n.get('stat') | |
688 base = n.get('base') | |
689 html_str = html_str + "<tr ALIGN='center'><td>"+name+"</td><td>"+stat+"</td><td>"+base+"</td>" | |
690 stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 | |
691 mag = n.get('magmod') | |
692 misc = n.get('miscmod') | |
693 mod = str(self.get_mod(name)) | |
694 if mod >= 0: mod1 = "+" | |
695 else: mod1 = "" | |
696 html_str = html_str + "<td>"+str(stat_mod)+"</td><td>"+mag+"</td>" | |
697 html_str = html_str + '<td>'+misc+'</td><td>%s%s</td></tr>' % (mod1, mod) | |
698 html_str = html_str + "</table>" | |
699 return html_str | |
700 | |
701 #mark6 | |
702 class save_grid(wx.grid.Grid): | |
703 """grid for saves""" | |
704 def __init__(self, parent, handler): | |
705 pname = handler.xml.set("name", 'Saves') | |
706 self.hparent = handler #a 1.5002 allow ability to run up tree. | |
707 #a 1.5002 in this case, we need the functional parent, not the invoking parent. | |
708 self.root = getRoot(self) | |
709 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
710 self.Bind(wx.EVT_SIZE, self.on_size) | |
711 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
712 self.handler = handler | |
713 saves = handler.xml.findall('save') | |
714 self.CreateGrid(len(saves),7) | |
715 self.SetRowLabelSize(0) | |
716 col_names = ['Save','Key','base','Abil','Magic','Misc','Total'] | |
717 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i]) | |
718 self.saves = saves | |
719 i = 0 | |
720 for i in range(len(saves)): self.refresh_row(i) | |
721 climber = parent | |
722 nameNode = climber.GetClassName() | |
723 while nameNode != 'wxFrame': | |
724 climber = climber.parent | |
725 nameNode = climber.GetClassName() | |
726 masterFrame=climber | |
727 masterFrame.refresh_data=self.refresh_data | |
728 handler.saveGridFrame.append(masterFrame) | |
729 | |
730 def on_cell_change(self,evt): | |
731 row = evt.GetRow() | |
732 col = evt.GetCol() | |
733 value = self.GetCellValue(row,col) | |
734 try: | |
735 int(value) | |
736 if col == 2: self.saves[row].set('base',value) | |
737 elif col == 4: self.saves[row].set('magmod',value) | |
738 elif col == 5: self.saves[row].set('miscmod',value) | |
739 self.refresh_row(row) | |
740 except: self.SetCellValue(row,col,"0") | |
741 | |
742 def refresh_row(self,rowi): | |
743 s = self.saves[rowi] | |
744 name = s.get('name') | |
745 self.SetCellValue(rowi,0,name) | |
746 self.SetReadOnly(rowi,0) | |
747 stat = s.get('stat') | |
748 self.SetCellValue(rowi,1,stat) | |
749 self.SetReadOnly(rowi,1) | |
750 self.SetCellValue(rowi,2,s.get('base')) | |
751 self.SetCellValue(rowi,3,str(self.root.abilities.get_mod(stat))) | |
752 self.SetReadOnly(rowi,3) | |
753 self.SetCellValue(rowi,4,s.get('magmod')) | |
754 self.SetCellValue(rowi,5,s.get('miscmod')) | |
755 mod = str(self.handler.get_mod(name)) | |
756 self.SetCellValue(rowi,6,mod) | |
757 self.SetReadOnly(rowi,6) | |
758 | |
759 def on_size(self,evt): | |
760 (w,h) = self.GetClientSizeTuple() | |
761 cols = self.GetNumberCols() | |
762 col_w = w/(cols+2) | |
763 self.SetColSize(0,col_w*3) | |
764 for i in range(1,cols): self.SetColSize(i,col_w) | |
765 evt.Skip() | |
766 self.Refresh() | |
767 | |
768 def refresh_data(self): | |
769 for r in range(self.GetNumberRows()): self.refresh_row(r) | |
770 | |
771 class dnd35skillsnfeats(dnd35_char_child): | |
772 """ Node handler for a dnd35 charactor | |
773 <nodehandler name='?' module='dnd35' class='dnd35char_handler2' /> | |
774 """ | |
775 def __init__(self,xml_dom,tree_node,parent): | |
776 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
777 self.root = getRoot(self) #a 1.6009 | |
778 node_handler.__init__(self,xml_dom,tree_node) | |
779 dnd35_char_child.__init__(self,xml_dom,tree_node,parent) | |
780 self.frame = component.get('frame') | |
781 self.child_handlers = {} | |
782 self.new_child_handler('skills','Skills',dnd35skill,'book') | |
783 self.new_child_handler('feats','Feats',dnd35feats,'book') | |
784 self.myeditor = None | |
785 | |
786 def new_child_handler(self,tag,text,handler_class,icon='gear'): | |
787 node_list = self.xml.findall(tag) | |
788 tree = self.tree | |
789 i = self.tree.icons[icon] | |
790 new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) | |
791 handler = handler_class(node_list[0],new_tree_node,self) | |
792 tree.SetPyData(new_tree_node,handler) | |
793 self.child_handlers[tag] = handler | |
794 | |
795 def get_design_panel(self,parent): | |
796 return tabbed_panel(parent,self,1) | |
797 | |
798 def get_use_panel(self,parent): | |
799 return tabbed_panel(parent,self,2) | |
800 | |
801 class skills_char_child(node_handler): | |
802 """ Node Handler for skill. This handler will be | |
803 created by dnd35char_handler. | |
804 """ | |
805 def __init__(self,xml_dom,tree_node,parent): | |
806 node_handler.__init__(self,xml_dom,tree_node) | |
807 self.char_hander = parent | |
808 self.drag = False | |
809 self.frame = component.get('frame') | |
810 self.myeditor = None | |
811 | |
812 def on_drop(self,evt): | |
813 pass | |
814 | |
815 def on_rclick(self,evt): | |
816 pass | |
817 | |
818 def on_ldclick(self,evt): | |
819 return | |
820 | |
821 def on_html(self,evt): | |
822 html_str = self.tohtml() | |
823 wnd = http_html_window(self.frame.note,-1) | |
824 wnd.title = self.xml.get('name') | |
825 self.frame.add_panel(wnd) | |
826 wnd.SetPage(html_str) | |
827 | |
828 def get_design_panel(self,parent): | |
829 pass | |
830 | |
831 def get_use_panel(self,parent): | |
832 return self.get_design_panel(parent) | |
833 | |
834 def delete(self): | |
835 pass | |
836 | |
837 class dnd35skill(skills_char_child): | |
838 """ Node Handler for skill. This handler will be | |
839 created by dnd35char_handler. | |
840 """ | |
841 def __init__(self,xml_dom,tree_node,parent): | |
842 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
843 #a 1.5002 Need the functional parent, not the invoking parent. | |
844 self.root = getRoot(self) #a 1.5002 | |
845 self.root.skills = self #a 1.6009 | |
846 | |
847 skills_char_child.__init__(self,xml_dom,tree_node,parent) | |
848 tree = self.tree | |
849 icons = self.tree.icons | |
850 node_list = self.xml.findall('skill') | |
851 | |
852 self.skills={} | |
853 #Adding code to not display skills you can not use -mgt | |
854 for n in node_list: | |
855 name = n.get('name') | |
856 self.skills[name] = n | |
857 skill_check = self.skills[name] | |
858 ranks = int(skill_check.get('rank')) | |
859 trained = int(skill_check.get('untrained')) | |
860 if ranks > 0 or trained == 1: | |
861 new_tree_node = tree.AppendItem(self.mytree_node,name, | |
862 icons['gear'],icons['gear']) | |
863 else: continue | |
864 tree.SetPyData(new_tree_node,self) | |
865 | |
866 def refresh_skills(self): | |
867 #Adding this so when you update the grid the tree will reflect | |
868 #The change. -mgt | |
869 tree = self.tree | |
870 icons = self.tree.icons | |
871 tree.CollapseAndReset(self.mytree_node) | |
872 node_list = self.xml.findall('skill') | |
873 | |
874 self.skills={} | |
875 for n in node_list: | |
876 name = n.get('name') | |
877 self.skills[name] = n | |
878 skill_check = self.skills[name] | |
879 ranks = int(skill_check.get('rank')) | |
880 trained = int(skill_check.get('untrained')) | |
881 if ranks > 0 or trained == 1: | |
882 new_tree_node = tree.AppendItem(self.mytree_node,name, | |
883 icons['gear'],icons['gear']) | |
884 else: continue | |
885 tree.SetPyData(new_tree_node,self) | |
886 | |
887 def get_mod(self,name): | |
888 skill = self.skills[name] | |
889 stat = skill.get('stat') | |
890 stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 | |
891 rank = int(skill.get('rank')) | |
892 misc = int(skill.get('misc')) | |
893 total = stat_mod + rank + misc | |
894 return total | |
895 | |
896 def on_rclick(self,evt): | |
897 item = self.tree.GetSelection() | |
898 name = self.tree.GetItemText(item) | |
899 if item == self.mytree_node: return | |
900 ac = self.root.ac.get_check_pen() #a 1.5002 for 1.5004 verify fix. | |
901 skill = self.skills[name] | |
902 untr = skill.get('untrained') #a 1.6004 | |
903 rank = skill.get('rank') #a 1.6004 | |
904 if eval('%s == 0' % (untr)): #a 1.6004 | |
905 if eval('%s == 0' % (rank)): #a 1.6004 | |
906 res = 'You fumble around, accomplishing nothing' #a 1.6004 | |
907 txt = '%s Skill Check: %s' % (name, res) #a 1.6004 | |
908 chat = self.chat #a 1.6004 | |
909 chat.Post(txt,True,True) #a 1.6004 | |
910 return #a 1.6004 | |
911 armor = '' | |
912 acCp = '' | |
913 if ac < 0: #acCp >= 1 #m 1.5004 this is stored as negatives. | |
914 armorCheck = int(skill.get('armorcheck')) | |
915 if armorCheck == 1: | |
916 acCp=ac | |
917 armor = '(includes Armor Penalty of %s)' % (acCp) | |
918 if item == self.mytree_node: | |
919 dnd35_char_child.on_ldclick(self,evt) | |
920 else: | |
921 mod = self.get_mod(name) | |
922 if mod >= 0: mod1 = "+" | |
923 else: mod1 = "" | |
924 chat = self.chat | |
925 txt = '%s Skill Check: [1d20%s%s%s] %s' % ( | |
926 name, mod1, mod, acCp, armor) | |
927 chat.ParsePost(txt,True,True) | |
928 | |
929 def get_design_panel(self,parent): | |
930 wnd = outline_panel(parent,self,skill_grid,"Skills") | |
931 wnd.title = "Skills (edit)" | |
932 return wnd | |
933 | |
934 def tohtml(self): | |
935 html_str = """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > | |
936 <th width='30%'>Skill</th><th>Key</th> | |
937 <th>Rank</th><th>Abil</th><th>Misc</th><th>Total</th></tr>""" | |
938 node_list = self.xml.findall('skill') | |
939 | |
940 for n in node_list: | |
941 name = n.get('name') | |
942 stat = n.get('stat') | |
943 rank = n.get('rank') | |
944 untr = n.get('untrained') #a 1.6004 | |
945 #Filter unsuable skills out of pretty print -mgt | |
946 if eval('%s > 0' % (rank)) or eval('%s == 1' % (untr)): | |
947 if eval('%s >=1' % (rank)): | |
948 html_str += "<tr ALIGN='center' bgcolor='#CCCCFF'><td>" #a 1.6004 | |
949 html_str += name+"</td><td>"+stat+"</td><td>"+rank+"</td>" | |
950 elif eval('%s == 1' % (untr)): #a 1.6004 | |
951 html_str += "<tr ALIGN='center' bgcolor='#C0FF40'><td>" #a 1.6004 | |
952 html_str += name+"</td><td>"+stat+"</td><td>"+rank+"</td>" #a 1.6004 | |
953 else: | |
954 html_str += "<tr ALIGN='center'><td>"+name+"</td><td>" | |
955 html_str += stat+"</td><td>"+rank+"</td>" | |
956 else: continue | |
957 stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 | |
958 misc = n.get('misc') | |
959 mod = str(self.get_mod(name)) | |
960 if mod >= 0: mod1 = "+" | |
961 else: mod1 = "" | |
962 html_str += "<td>"+str(stat_mod)+"</td><td>"+misc #m 1.6009 str() | |
963 html_str += '</td><td>%s%s</td></tr>' % (mod1, mod) | |
964 html_str = html_str + "</table>" | |
965 return html_str | |
966 | |
967 | |
968 class skill_grid(wx.grid.Grid): | |
969 """ panel for skills """ | |
970 def __init__(self, parent, handler): | |
971 self.hparent = handler #a 1.5002 need function parent, not invoker | |
972 self.root = getRoot(self) #a 1.5002 | |
973 pname = handler.xml.set("name", 'Skills') | |
974 | |
975 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
976 self.Bind(wx.EVT_SIZE, self.on_size) | |
977 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
978 self.handler = handler | |
979 skills = handler.xml.findall('skill') | |
980 self.CreateGrid(len(skills),6) | |
981 self.SetRowLabelSize(0) | |
982 col_names = ['Skill','Key','Rank','Abil','Misc','Total'] | |
983 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i]) | |
984 rowi = 0 | |
985 self.skills = skills | |
986 for i in range(len(skills)): self.refresh_row(i) | |
987 | |
988 def on_cell_change(self,evt): | |
989 row = evt.GetRow() | |
990 col = evt.GetCol() | |
991 value = self.GetCellValue(row,col) | |
992 try: | |
993 int(value) | |
994 if col == 2: self.skills[row].set('rank',value) | |
995 elif col == 4: self.skills[row].set('misc',value) | |
996 self.refresh_row(row) | |
997 except: self.SetCellValue(row,col,"0") | |
998 self.handler.refresh_skills() | |
999 | |
1000 def refresh_row(self,rowi): | |
1001 s = self.skills[rowi] | |
1002 name = s.get('name') | |
1003 self.SetCellValue(rowi,0,name) | |
1004 self.SetReadOnly(rowi,0) | |
1005 stat = s.get('stat') | |
1006 self.SetCellValue(rowi,1,stat) | |
1007 self.SetReadOnly(rowi,1) | |
1008 self.SetCellValue(rowi,2,s.get('rank')) | |
1009 #self.SetCellValue(rowi,3,str(dnd_globals["stats"][stat])) #d 1.5002 | |
1010 if self.root.abilities: stat_mod=self.root.abilities.get_mod(stat) #a 1.5002 | |
151 | 1011 else: |
155 | 1012 stat_mod = -6 #a 1.5002 this can happen if code is changed so |
1013 print "Please advise dnd35 maintainer alert 1.5002 raised" | |
1014 | |
1015 self.SetCellValue(rowi,3,str(stat_mod)) #a 1.5002 | |
1016 self.SetReadOnly(rowi,3) | |
1017 self.SetCellValue(rowi,4,s.get('misc')) | |
1018 mod = str(self.handler.get_mod(name)) | |
1019 self.SetCellValue(rowi,5,mod) | |
1020 self.SetReadOnly(rowi,5) | |
1021 | |
1022 def on_size(self,evt): | |
1023 (w,h) = self.GetClientSizeTuple() | |
1024 cols = self.GetNumberCols() | |
1025 col_w = w/(cols+2) | |
1026 self.SetColSize(0,col_w*3) | |
1027 for i in range(1,cols): self.SetColSize(i,col_w) | |
1028 evt.Skip() | |
1029 self.Refresh() | |
1030 | |
1031 def refresh_data(self): | |
1032 for r in range(self.GetNumberRows()): self.refresh_row(r) | |
1033 | |
1034 | |
1035 class dnd35feats(skills_char_child): | |
1036 """ Node Handler for classes. This handler will be | |
1037 created by dnd35char_handler. | |
1038 """ | |
1039 def __init__(self,xml_dom,tree_node,parent): | |
1040 skills_char_child.__init__(self,xml_dom,tree_node,parent) | |
1041 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
1042 self.root = getRoot(self) #a 1.5002 | |
1043 self.root.feats = self #a 1.6009 | |
1044 | |
1045 | |
1046 def get_design_panel(self,parent): | |
1047 setTitle="Feats - " + self.root.general.charName #a 1.5010 | |
1048 wnd = outline_panel(parent,self,feat_panel,setTitle) #a 1.5010 | |
1049 wnd.title = "Feats" #d 1.5010 | |
1050 return wnd | |
1051 | |
1052 def tohtml(self): | |
1053 html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>Feats</th></tr><tr><td>" | |
1054 n_list = self.xml.getchildren() | |
1055 for n in n_list: html_str += n.get('name')+ ", " | |
1056 html_str = html_str[:len(html_str)-2] + "</td></tr></table>" | |
1057 return html_str | |
1058 | |
1059 class feat_panel(wx.Panel): | |
1060 def __init__(self, parent, handler): | |
1061 | |
1062 self.hparent = handler #a 1.5002 allow ability to run up tree. | |
1063 | |
1064 self.root = getRoot(self) #a 1.5002 | |
1065 pname = handler.xml.set("name", 'Feats') #d 1.5010 | |
1066 wx.Panel.__init__(self, parent, -1) | |
1067 self.grid = wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
1068 sizer = wx.BoxSizer(wx.VERTICAL) | |
1069 sizer.Add(self.grid, 1, wx.EXPAND) | |
1070 | |
1071 sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
1072 sizer1.Add(wx.Button(self, 10, "Remove Feat"), 0, wx.EXPAND) | |
1073 sizer1.Add(wx.Size(10,10)) | |
1074 sizer1.Add(wx.Button(self, 20, "Add Feat"), 0, wx.EXPAND) | |
1075 | |
1076 sizer.Add(sizer1, 0, wx.EXPAND) | |
1077 self.sizer = sizer | |
1078 | |
1079 self.SetSizer(self.sizer) | |
1080 self.SetAutoLayout(True) | |
1081 self.Fit() | |
1082 | |
1083 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) | |
1084 self.Bind(wx.EVT_BUTTON, self.on_add, id=20) | |
1085 | |
1086 n_list = handler.xml.getchildren() | |
1087 self.n_list = n_list | |
1088 self.xml = handler.xml | |
1089 self.grid.CreateGrid(len(n_list),3,1) | |
1090 self.grid.SetRowLabelSize(0) | |
1091 self.grid.SetColLabelValue(0,"Feat") | |
1092 self.grid.SetColLabelValue(1,"Reference") | |
1093 self.grid.SetColLabelValue(2,"Description") #m 1.6 typo correction. | |
1094 wrap = wx.grid.GridCellAutoWrapStringRenderer() | |
1095 attr = wx.grid.GridCellAttr() | |
1096 attr.SetRenderer(wrap) | |
1097 self.grid.SetColAttr(2, attr) | |
1098 for i in range(len(n_list)): self.refresh_row(i) | |
1099 self.temp_dom = None | |
1100 | |
1101 def refresh_row(self,i): | |
1102 feat = self.n_list[i] | |
1103 name = feat.get('name') | |
1104 type = feat.get('type') | |
1105 desc = feat.get('desc') #m 1.6 correct typo | |
1106 self.grid.SetCellValue(i,0,name) | |
1107 self.grid.SetReadOnly(i,0) | |
1108 self.grid.SetCellValue(i,1,type) | |
1109 self.grid.SetReadOnly(i,1) | |
1110 self.grid.SetCellValue(i,2,desc) #m 1.6 correct typo | |
1111 self.grid.SetReadOnly(i,2) | |
1112 self.grid.AutoSizeColumn(0) | |
1113 self.grid.AutoSizeColumn(1) | |
1114 self.grid.AutoSizeColumn(2, False) | |
1115 self.grid.AutoSizeRow(i) | |
1116 | |
1117 def on_remove(self,evt): | |
1118 rows = self.grid.GetNumberRows() | |
1119 for i in range(rows): | |
1120 if self.grid.IsInSelection(i,0): | |
1121 self.grid.DeleteRows(i) | |
1122 self.xml.remove(self.n_list[i]) | |
1123 | |
1124 def on_add(self,evt): | |
1125 | |
1126 if not self.temp_dom: | |
1127 tree = parse(dir_struct["dnd35"]+"dnd35feats.xml") | |
1128 xml_dom = tree.getroot() | |
1129 self.temp_dom = xml_dom | |
1130 f_list = self.temp_dom.findall('feat') | |
1131 opts = [] | |
1132 for f in f_list: | |
1133 opts.append(f.get('name') + " - [" + | |
1134 f.get('type') + "] - " + f.get('desc')) | |
1135 dlg = wx.SingleChoiceDialog(self,'Choose Feat','Feats',opts) | |
1136 if dlg.ShowModal() == wx.ID_OK: | |
1137 i = dlg.GetSelection() | |
1138 new_node = self.xml.append(f_list[i]) | |
1139 self.grid.AppendRows(1) | |
82
2fa8bd6785a5
TerminalWriter's colors are nice, but if no debug console is open it causes the software to look for one until a recursion error is created. Crash reports are sent to the debug console and a pop-up tells the user one has happened. Fix to chat window from SnowDog.
sirebral
parents:
71
diff
changeset
|
1140 self.refresh_row(self.grid.GetNumberRows()-1) |
2fa8bd6785a5
TerminalWriter's colors are nice, but if no debug console is open it causes the software to look for one until a recursion error is created. Crash reports are sent to the debug console and a pop-up tells the user one has happened. Fix to chat window from SnowDog.
sirebral
parents:
71
diff
changeset
|
1141 f_list=0; opts=0 |
155 | 1142 dlg.Destroy() |
1143 | |
1144 | |
1145 def on_size(self,event): | |
1146 s = self.GetClientSizeTuple() | |
1147 self.grid.SetDimensions(0,0,s[0],s[1]-25) | |
1148 self.sizer.SetDimension(0,s[1]-25,s[0],25) | |
1149 (w,h) = self.grid.GetClientSizeTuple() | |
1150 cols = self.grid.GetNumberCols() | |
1151 col_w = w/(cols) | |
1152 for i in range(0,cols): self.grid.SetColSize(i,col_w) | |
1153 | |
1154 class dnd35combat(dnd35_char_child): | |
1155 """ Node handler for a dnd35 charactor | |
1156 <nodehandler name='?' module='dnd35' class='dnd35char_handler2' /> | |
1157 """ | |
1158 def __init__(self,xml_dom,tree_node,parent): | |
1159 | |
1160 node_handler.__init__(self,xml_dom,tree_node) | |
1161 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
1162 self.root = getRoot(self) #a 1.5012 | |
1163 #mark3 | |
1164 dnd35_char_child.__init__(self,xml_dom,tree_node,parent) | |
1165 self.frame = component.get('frame') | |
1166 self.child_handlers = {} | |
1167 self.new_child_handler('hp','Hit Points',dnd35hp,'gear') | |
1168 self.new_child_handler('attacks','Attacks',dnd35attacks,'spears') | |
1169 self.new_child_handler('ac','Armor',dnd35armor,'spears') | |
1170 self.myeditor = None | |
1171 | |
1172 def new_child_handler(self,tag,text,handler_class,icon='gear'): | |
1173 node_list = self.xml.findall(tag) | |
1174 tree = self.tree | |
1175 i = self.tree.icons[icon] | |
1176 new_tree_node = tree.AppendItem(self.mytree_node,text,i,i) | |
1177 handler = handler_class(node_list[0],new_tree_node,self) | |
1178 tree.SetPyData(new_tree_node,handler) | |
1179 self.child_handlers[tag] = handler | |
1180 | |
1181 def get_design_panel(self,parent): | |
1182 return tabbed_panel(parent,self,1) | |
1183 | |
1184 def get_use_panel(self,parent): | |
1185 return tabbed_panel(parent,self,2) | |
1186 | |
1187 | |
1188 class combat_char_child(node_handler): | |
1189 """ Node Handler for combat. This handler will be | |
1190 created by dnd35char_handler. | |
1191 """ | |
1192 def __init__(self,xml_dom,tree_node,parent): | |
1193 node_handler.__init__(self,xml_dom,tree_node) | |
1194 self.char_hander = parent | |
1195 self.drag = False | |
1196 self.frame = component.get('frame') | |
1197 self.myeditor = None | |
1198 | |
1199 def on_drop(self,evt): | |
1200 pass | |
1201 | |
1202 def on_rclick(self,evt): | |
1203 pass | |
1204 | |
1205 def on_ldclick(self,evt): | |
1206 return | |
1207 | |
1208 def on_html(self,evt): | |
1209 html_str = self.tohtml() | |
1210 wnd = http_html_window(self.frame.note,-1) | |
1211 wnd.title = self.xml.get('name') | |
1212 self.frame.add_panel(wnd) | |
1213 wnd.SetPage(html_str) | |
1214 | |
1215 def get_design_panel(self,parent): | |
1216 pass | |
1217 | |
1218 def get_use_panel(self,parent): | |
1219 return self.get_design_panel(parent) | |
1220 | |
1221 def delete(self): | |
1222 pass | |
1223 | |
1224 class dnd35hp(combat_char_child): | |
1225 """ Node Handler for hit points. This handler will be | |
1226 created by dnd35char_handler. | |
1227 """ | |
1228 def __init__(self,xml_dom,tree_node,parent): | |
1229 combat_char_child.__init__(self,xml_dom,tree_node,parent) | |
1230 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
1231 self.root = getRoot(self) #a 1.6009 | |
1232 self.root.hp = self #a 1.6009 | |
1233 | |
1234 def get_design_panel(self,parent): | |
1235 wnd = outline_panel(parent,self,hp_panel,"Hit Points") | |
1236 wnd.title = "Hit Points" | |
1237 return wnd | |
1238 | |
1239 def on_rclick( self, evt ): | |
1240 chp = self.xml.get('current') | |
1241 mhp = self.xml.get('max') | |
1242 txt = '((HP: %s / %s))' % ( chp, mhp ) | |
1243 self.chat.ParsePost( txt, True, True ) | |
1244 | |
1245 def tohtml(self): | |
1246 html_str = "<table width=100% border=1 >" | |
1247 html_str += "<tr BGCOLOR=#E9E9E9 ><th colspan=4>Hit Points</th></tr>" | |
1248 html_str += "<tr><th>Max:</th>" | |
1249 html_str += "<td>"+self.xml.get('max')+"</td>" | |
1250 html_str += "<th>Current:</th>" | |
1251 html_str += "<td>"+self.xml.get('current')+"</td>" | |
1252 html_str += "</tr></table>" | |
1253 return html_str | |
1254 | |
1255 class hp_panel(wx.Panel): | |
1256 def __init__(self, parent, handler): | |
1257 wx.Panel.__init__(self, parent, -1) | |
1258 self.hparent = handler | |
1259 pname = handler.xml.set("name", 'HitPoints') | |
1260 self.sizer = wx.FlexGridSizer(2, 4, 2, 2) # rows, cols, hgap, vgap | |
1261 self.xml = handler.xml | |
1262 self.sizer.AddMany([ (wx.StaticText(self, -1, "HP Current:"), 0, | |
1263 wx.ALIGN_CENTER_VERTICAL), | |
1264 (wx.TextCtrl(self, HP_CUR, | |
1265 self.xml.get('current')), 0, wx.EXPAND), | |
1266 (wx.StaticText(self, -1, "HP Max:"), 0, wx.ALIGN_CENTER_VERTICAL), | |
1267 (wx.TextCtrl(self, HP_MAX, self.xml.get('max')), | |
1268 0, wx.EXPAND), | |
1269 ]) | |
1270 self.sizer.AddGrowableCol(1) | |
1271 self.SetSizer(self.sizer) | |
1272 self.SetAutoLayout(True) | |
1273 self.Fit() | |
1274 | |
1275 self.Bind(wx.EVT_TEXT, self.on_text, id=HP_MAX) | |
1276 self.Bind(wx.EVT_TEXT, self.on_text, id=HP_CUR) | |
1277 | |
1278 def on_text(self,evt): | |
1279 id = evt.GetId() | |
1280 if id == HP_CUR: self.xml.set('current',evt.GetString()) | |
1281 elif id == HP_MAX: self.xml.set('max',evt.GetString()) | |
1282 | |
1283 def on_size(self,evt): | |
1284 s = self.GetClientSizeTuple() | |
1285 self.sizer.SetDimension(0,0,s[0],s[1]) | |
1286 | |
1287 class dnd35attacks(combat_char_child): | |
1288 """ Node Handler for attacks. This handler will be | |
1289 created by dnd35char_handler. | |
1290 """ | |
1291 def __init__(self,xml_dom,tree_node,parent): | |
1292 combat_char_child.__init__(self,xml_dom,tree_node,parent) | |
1293 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
1294 self.root = getRoot(self) #a 1.5002 | |
1295 self.root.attacks = self #a 1.6009 so others can find me. | |
1296 self.mrFrame = [] #a 1.9001 | |
1297 self.updateFootNotes = False | |
1298 self.updateFootNotes = False | |
1299 self.html_str = "<html><body>" | |
1300 self.html_str += ("<br /> This character has weapons with no "+ | |
1301 "footnotes. This program will "+ | |
1302 "add footnotes to the weapons which have names that still match "+ | |
1303 "the orginal names. If you have changed the weapon name, you "+ | |
1304 "will see some weapons with a footnote of 'X', you will have "+ | |
1305 "to either delete and re-add the weapon, or research "+ | |
1306 "and add the correct footnotes for the weapon.\n"+ | |
1307 "<br /> Please be aware, that only the bow/sling footnote is "+ | |
1308 "being used to affect changes to rolls; implemenation of other "+ | |
1309 "footnotes to automaticly adjust rolls will be completed as "+ | |
1310 "soon as time allows." + | |
1311 "<br /><br />Update to character:"+self.root.general.charName+ | |
1312 "<br /><br />"+ | |
1313 """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > | |
1314 <th width='80%'>Weapon Name</th><th>Added Footnote</th></tr>\n""") | |
1315 self.temp_dom={} | |
1316 node_list = self.xml.findall('melee') | |
1317 self.melee = node_list[0] | |
1318 node_list = self.xml.findall('ranged') | |
1319 self.ranged = node_list[0] | |
1320 self.refresh_weapons() | |
1321 if self.updateFootNotes == True: | |
1322 self.updateFootNotes = False | |
1323 name = self.root.general.charName | |
1324 self.html_str += "</table>" | |
1325 self.html_str += "</body> </html> " | |
1326 masterFrame = self.root.frame | |
1327 title = name+"'s weapons' update to have footnotes" | |
1328 fnFrame = wx.Frame(masterFrame, -1, title) | |
1329 fnFrame.panel = wx.html.HtmlWindow(fnFrame,-1) | |
1330 fnFrame.panel.SetPage(self.html_str) | |
1331 fnFrame.Show() | |
1332 | |
1333 #a 1.9001 this whole method | |
1334 def refreshMRdata(self): # refresh the data in the melee/ranged section | |
1335 # of the attack chart. | |
1336 # count backwards, maintains context despite "removes" | |
1337 for i in range(len(self.mrFrame)-1,-1,-1): #a 1.9001 | |
1338 x = self.mrFrame[i] | |
1339 if x == None: x.refreshMRdata() #a 1.9001 | |
1340 else: self.mrFrame.remove(x) | |
1341 | |
1342 def refresh_weapons(self): | |
1343 self.weapons = {} | |
1344 | |
1345 tree = self.tree | |
1346 icons = self.tree.icons | |
1347 tree.CollapseAndReset(self.mytree_node) | |
1348 node_list = self.xml.findall('weapon') | |
1349 for n in node_list: | |
1350 name = n.get('name') | |
1351 fn = safeGetAttr(n,'fn') #a 1.5012 can be removed when | |
1352 if fn == None:#a 1.5012 | |
1353 self.updateFootNotes=True | |
1354 self.updateFootN(n) #a 1.5012 | |
1355 new_tree_node = tree.AppendItem( | |
1356 self.mytree_node,name,icons['sword'],icons['sword']) | |
1357 tree.SetPyData(new_tree_node,self) | |
1358 self.weapons[name]=n | |
1359 | |
1360 def updateFootN(self,n):#a 1.5012 this whole function | |
1361 if not self.temp_dom: | |
1362 tree = parse(dir_struct["dnd35"]+"dnd35weapons.xml") | |
1363 self.temp_dom = tree.getroot() | |
1364 nameF = n.get('name') | |
1365 w_list = self.temp_dom.findall('weapon') | |
1366 found = False | |
1367 for w in w_list: | |
1368 if nameF == w.get('name'): | |
1369 found = True | |
1370 fnN = safeGetAttr(n,'fn') | |
1371 if fnN == None or fnN == 'None': | |
1372 fnW = w.get('fn') | |
1373 self.html_str += ("<tr ALIGN='center'><td>"+nameF+"</td>"+ | |
1374 "<td>"+fnW+"</td></tr>\n") | |
1375 n.set('fn',fnW) | |
1376 break | |
1377 if not found: | |
1378 self.html_str += ("<tr ALIGN='center'><td>"+nameF+" - Custom "+ | |
1379 "Weapon, research "+ | |
1380 "and update manually; setting footnote to indicate custom</td>"+ | |
1381 "<td>"+'X'+"</td></tr>\n") | |
1382 n.set('fn','X') | |
1383 | |
1384 | |
1385 def get_mod(self,type='m'): | |
1386 (base, base2, base3, base4, base5, base6, stat_mod, misc) \ | |
1387 = self.get_attack_data(type) | |
1388 return int(base + misc + int(stat_mod)) | |
1389 | |
1390 def get_attack_data(self,type='m'): | |
1391 if type=='m' or type=='0': | |
1392 stat = 'Str' #m was dnd_globals["stats"]['Str'] 1.5002 | |
1393 temp = self.melee | |
1394 else: | |
1395 stat = 'Dex' #m was dnd_globals["stats"]['Dex'] 1.5002 | |
1396 temp = self.ranged | |
1397 stat_mod = -7 | |
1398 stat_mod = self.root.abilities.get_mod(stat) #a 1.5002 | |
1399 base = int(temp.get('base')) | |
1400 base2 = int(temp.get('second')) | |
1401 base3 = int(temp.get('third')) | |
1402 base4 = int(temp.get('forth')) | |
1403 base5 = int(temp.get('fifth')) | |
1404 base6 = int(temp.get('sixth')) | |
1405 misc = int(temp.get('misc')) | |
1406 return (base, base2, base3, base4, base5, base6, stat_mod ,misc) | |
1407 | |
1408 def on_rclick(self,evt): | |
1409 item = self.tree.GetSelection() | |
1410 name = self.tree.GetItemText(item) | |
1411 if item == self.mytree_node: return | |
1412 else: | |
1413 mod = int(self.weapons[name].get('mod')) | |
1414 wepMod = mod #a 1.5008 | |
1415 footNotes = safeGetAttr(self.weapons[name],'fn','') | |
1416 cat = self.weapons[name].get('category') #a1.6001 | |
1417 result = split(cat,"-",2) #a 1.6001 | |
1418 if len(result) < 2: #a 1.6021 this if & else | |
1419 print "warning: 1.6002 unable to interpret weapon category" | |
1420 print "format 'type weapon-[Range|Melee]', probably missing" | |
1421 print "the hyphen. Assuming Melee" | |
1422 print "weapon name: ",name | |
1423 tres="Melee" | |
1424 else: | |
1425 tres=result[1] | |
1426 if tres == 'Melee': rangeOrMelee = 'm' | |
1427 elif tres == 'Ranged': rangeOrMelee = 'r' | |
1428 else: | |
1429 print "warning: 1.6001 unable to interpret weapon category" | |
1430 print "treating weapon as Melee, please correct xml" | |
1431 print "weapon name:",name | |
1432 rangeOrMelee ='m' | |
1433 mod = mod + self.get_mod(rangeOrMelee) #a 1.5008 | |
1434 chat = self.chat | |
1435 dmg = self.weapons[name].get('damage') | |
1436 | |
1437 #a 1.6003 start code fix instance a | |
1438 result = split(dmg,"/",2) | |
1439 dmg = result[0] | |
1440 monkLvl = self.root.classes.get_class_lvl('Monk') # a 1.5002 | |
1441 if find(dmg, "Monk Med") > -1: | |
1442 if monkLvl == None: #a 1.5009 | |
1443 txt = 'Attempting to use monk attack, but has no monk ' | |
1444 txt += 'levels, please choose a different attack.' | |
1445 chat.ParsePost( txt, True, True ) #a 1.5009 | |
1446 return #a 1.5009 | |
1447 else: #a 1.5009 | |
1448 lvl=int(monkLvl) | |
1449 if lvl <= 3: dmg = dmg.replace("Monk Med", "1d6") | |
1450 elif lvl <= 7: dmg = dmg.replace("Monk Med", "1d8") | |
1451 elif lvl <= 11: dmg = dmg.replace("Monk Med", "1d10") | |
1452 elif lvl <= 15: dmg = dmg.replace("Monk Med", "2d6") | |
1453 elif lvl <= 19: dmg = dmg.replace("Monk Med", "2d8") | |
1454 elif lvl <= 20: dmg = dmg.replace("Monk Med", "2d10") | |
1455 if find(dmg, "Monk Small") > -1: | |
1456 if monkLvl == None: #a 1.5009 | |
1457 txt = 'Attempting to use monk attack, but has no monk ' | |
1458 txt += 'levels, please choose a different attack.' | |
1459 chat.ParsePost( txt, True, True ) #a 1.5009 | |
1460 return #a 1.5009 | |
1461 else: #a 1.5009 | |
1462 lvl=int(monkLvl) | |
1463 if lvl <= 3: dmg = dmg.replace("Monk Small", "1d4") | |
1464 elif lvl <= 7: dmg = dmg.replace("Monk Small", "1d6") | |
1465 elif lvl <= 11: dmg = dmg.replace("Monk Small", "1d8") | |
1466 elif lvl <= 15: dmg = dmg.replace("Monk Small", "1d10") | |
1467 elif lvl <= 19: dmg = dmg.replace("Monk Small", "2d6") | |
1468 elif lvl <= 20: dmg = dmg.replace("Monk Small", "2d8") | |
1469 if find(dmg, "Monk Large") > -1: | |
1470 if monkLvl == None: #a 1.5009 | |
1471 txt = 'Attempting to use monk attack, but has no monk ' | |
1472 txt += 'levels, please choose a different attack.' | |
1473 chat.ParsePost( txt, True, True ) #a 1.5009 | |
1474 return #a 1.5009 | |
1475 else: #a 1.5009 | |
1476 lvl=int(monkLvl) | |
1477 if lvl <= 3: dmg = dmg.replace("Monk Large", "1d8") | |
1478 elif lvl <= 7: dmg = dmg.replace("Monk Large", "2d6") | |
1479 elif lvl <= 11: dmg = dmg.replace("Monk Large", "2d8") | |
1480 elif lvl <= 15: dmg = dmg.replace("Monk Large", "3d6") | |
1481 elif lvl <= 19: dmg = dmg.replace("Monk Large", "3d8") | |
1482 elif lvl <= 20: dmg = dmg.replace("Monk Large", "4d8") | |
1483 flurry = False | |
1484 str_mod = self.root.abilities.get_mod('Str') #a 1.5007,11,12,13 | |
1485 if rangeOrMelee == 'r': #a 1.5008 | |
1486 #if off_hand == True then stat_mod = stat_mod/2 #o 1.5013 | |
1487 #c 1.5007 ranged weapons normally get no str mod | |
1488 if find(footNotes,'b') > -1:#a 1.5012 if it's a bow | |
1489 if str_mod >= 0: str_mod = 0 | |
1490 else: str_mod = 0 | |
1491 mod2 = "" | |
1492 if str_mod >= 0: mod2 = "+" #1.6 tidy up code. | |
1493 aStrengthMod = mod2 + str(str_mod) #a 1.5008 applicable strength mod | |
1494 if find(name ,"Flurry of Blows") > -1: flurry = True | |
1495 (base, base2, base3, base4, base5, base6, stat_mod, misc) = self.get_attack_data(rangeOrMelee) #a 1.5008 | |
1496 name = name.replace('(Monk Med)', '') | |
1497 name = name.replace('(Monk Small)', '') | |
1498 if not flurry: | |
1499 if name == 'Shuriken': | |
1500 for n in xrange(3): | |
1501 self.sendRoll(base, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod, rollAnyWay=True) | |
1502 self.sendRoll(base2, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1503 self.sendRoll(base3, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1504 self.sendRoll(base4, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1505 self.sendRoll(base5, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1506 self.sendRoll(base6, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1507 else: | |
1508 self.sendRoll(base, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod, rollAnyWay=True) | |
1509 self.sendRoll(base2, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1510 self.sendRoll(base3, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1511 self.sendRoll(base4, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1512 self.sendRoll(base5, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1513 self.sendRoll(base6, stat_mod, misc, wepMod, name, '', dmg, aStrengthMod) | |
1514 else: | |
1515 if monkLvl == None: | |
1516 txt = 'Attempting to use monk attack, but has no monk ' | |
1517 txt += 'levels, please choose a different attack.' | |
1518 chat.ParsePost( txt, True, True ) #a 1.5009 | |
1519 return | |
1520 else: | |
1521 lvl = int(monkLvl) | |
1522 if lvl <= 4: | |
1523 flu = '-2' | |
1524 atks = False | |
1525 elif lvl <= 8: | |
1526 flu = '-1' | |
1527 atks = False | |
1528 elif lvl <= 10: | |
1529 flu = '' | |
1530 atks = False | |
1531 elif lvl <= 20: | |
1532 flu = '' | |
1533 atks = True | |
1534 | |
1535 self.sendRoll(base, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod, rollAnyWay=True) | |
1536 self.sendRoll(base, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod, rollAnyWay=True) | |
1537 if atks: self.sendRoll(base, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod, rollAnyWay=True) | |
1538 self.sendRoll(base2, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod) | |
1539 self.sendRoll(base3, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod) | |
1540 self.sendRoll(base4, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod) | |
1541 self.sendRoll(base5, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod) | |
1542 self.sendRoll(base6, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod) | |
1543 | |
1544 def sendRoll(self, base, stat_mod, misc, wepMod, name, flu, dmg, aStrengthMod, rollAnyWay=False): | |
1545 if base != 0 or rollAnyWay: | |
1546 base = base + int(stat_mod) + misc + wepMod #m 1.5008 | |
1547 if base >= 0: mod1 = "+" | |
1548 else: mod1 = "" | |
1549 txt = ' %s Attack Roll: <b>[1d20%s%s%s]</b>' % (name, mod1, base, flu) | |
1550 txt += ' ===> Damage: <b>[%s%s]</b>' % (dmg, aStrengthMod) | |
1551 self.chat.ParsePost( txt, True, True ) | |
1552 | |
1553 def get_design_panel(self,parent): | |
1554 wnd = outline_panel(parent,self,attack_panel,"Attacks") | |
1555 wnd.title = "Attacks" | |
1556 return wnd | |
1557 | |
1558 def tohtml(self): | |
1559 melee = self.get_attack_data('m') | |
1560 ranged = self.get_attack_data('r') | |
1561 html_str = ("""<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 >"""+ | |
1562 "<th>Attack</th><th>Total</th><th >Base</th>"+ | |
1563 "<th>Abil</th><th>Misc</th></tr>") | |
1564 html_str += "<tr ALIGN='center' ><th >Melee:</th>" | |
1565 html_str += "<td>"+str(melee[0]+melee[1]+melee[2])+"</td>" | |
1566 html_str += "<td>"+str(melee[0])+"</td>" | |
1567 html_str += "<td>"+str(melee[1])+"</td>" | |
1568 html_str += "<td>"+str(melee[2])+"</td></tr>" | |
1569 | |
1570 html_str += "<tr ALIGN='center' ><th >Ranged:</th>" | |
1571 html_str += "<td>"+str(ranged[0]+ranged[1]+ranged[2])+"</td>" | |
1572 html_str += "<td>"+str(ranged[0])+"</td>" | |
1573 html_str += "<td>"+str(ranged[1])+"</td>" | |
1574 html_str += "<td>"+str(ranged[2])+"</td></tr></table>" | |
1575 | |
1576 n_list = self.xml.findall('weapon') | |
1577 for n in n_list: | |
1578 mod = n.get('mod') | |
1579 if mod >= 0: mod1 = "+" | |
1580 else: mod1 = "" | |
1581 ran = n.get('range') | |
1582 total = str(int(mod) + self.get_mod(ran)) | |
1583 html_str += """<P><table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > | |
1584 <th colspan=2>Weapon</th> | |
1585 <th>Attack</th><th >Damage</th><th>Critical</th></tr>""" | |
1586 html_str += "<tr ALIGN='center' ><td colspan=2>" | |
1587 html_str += n.get('name')+"</td><td>"+total+"</td>" | |
1588 html_str += "<td>"+n.get('damage')+"</td><td>" | |
1589 html_str += n.get('critical')+"</td></tr>" | |
1590 html_str += """<tr BGCOLOR=#E9E9E9 ><th>Range</th><th>Weight</th> | |
1591 <th>Type</th><th>Size</th><th>Misc Mod</th></tr>""" | |
1592 html_str += "<tr ALIGN='center'><td>"+ran+"</td><td>" | |
1593 html_str += n.get('weight')+"</td>" | |
1594 html_str += "<td>"+n.get('type')+"</td><td>" | |
1595 html_str += n.get('size')+"</td>" | |
1596 html_str += '<td>%s%s</td></tr>' % (mod1, mod) | |
1597 html_str += """<tr><th BGCOLOR=#E9E9E9 colspan=2>Footnotes:</th>""" | |
1598 html_str += "<th colspan=3>"+safeGetAttr(n,'fn','')+"</th></tr>" | |
1599 html_str += '</table>' | |
1600 return html_str | |
1601 | |
1602 class attack_grid(wx.grid.Grid): | |
1603 """grid for attacks""" | |
1604 def __init__(self, parent, handler): | |
1605 pname = handler.xml.set("name", 'Melee') | |
1606 self.hparent = handler | |
1607 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
1608 self.root = getRoot(self) #a 1.9001 | |
1609 self.parent = parent | |
1610 self.handler = handler | |
1611 self.rows = (self.handler.melee,self.handler.ranged) | |
1612 self.CreateGrid(2,10) | |
1613 self.SetRowLabelSize(0) | |
1614 col_names = ['Type','base','base 2','base 3','base 4','base 5', | |
1615 'base 6','abil','misc','Total'] | |
1616 for i in range(len(col_names)): self.SetColLabelValue(i,col_names[i]) | |
1617 self.SetCellValue(0,0,"Melee") | |
1618 self.SetCellValue(1,0,"Ranged") | |
1619 self.refresh_data() | |
1620 self.Bind(wx.EVT_SIZE, self.on_size) | |
1621 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
1622 climber = parent | |
1623 nameNode = climber.GetClassName() | |
1624 while nameNode != 'wxFrame': | |
1625 climber = climber.parent | |
1626 nameNode = climber.GetClassName() | |
1627 masterFrame=climber | |
1628 masterFrame.refreshMRdata=self.refresh_data | |
1629 | |
1630 handler.mrFrame.append(masterFrame) | |
1631 | |
1632 | |
1633 def on_cell_change(self,evt): | |
1634 row = evt.GetRow() | |
1635 col = evt.GetCol() | |
1636 value = self.GetCellValue(row,col) | |
1637 try: | |
1638 int(value) | |
1639 if col==1: self.rows[row].set('base',value) | |
1640 elif col== 2: self.rows[row].set('second',value) | |
1641 elif col== 3: self.rows[row].set('third',value) | |
1642 elif col== 4: self.rows[row].set('forth',value) | |
1643 elif col== 5: self.rows[row].set('fifth',value) | |
1644 elif col== 6: self.rows[row].set('sixth',value) | |
1645 elif col== 8: self.rows[row].set('misc',value) | |
1646 self.parent.refresh_data() | |
1647 except: self.SetCellValue(row,col,"0") | |
1648 | |
1649 def refresh_data(self): | |
1650 | |
1651 melee = self.handler.get_attack_data('m') | |
1652 ranged = self.handler.get_attack_data('r') | |
1653 tmelee = int(melee[0]) + int(melee[6]) + int(melee[7]) | |
1654 tranged = int(ranged[0]) + int(ranged[6]) + int(ranged[7]) | |
1655 for i in range(0,8): #a 1.5005 | |
1656 self.SetCellValue(0,i+1,str(melee[i])) | |
1657 self.SetCellValue(1,i+1,str(ranged[i])) | |
1658 self.SetCellValue(0,9,str(tmelee)) | |
1659 self.SetCellValue(1,9,str(tranged)) | |
1660 self.SetReadOnly(0,0) | |
1661 self.SetReadOnly(1,0) | |
1662 self.SetReadOnly(0,7) | |
1663 self.SetReadOnly(1,7) | |
1664 self.SetReadOnly(0,9) | |
1665 self.SetReadOnly(1,9) | |
1666 | |
1667 def on_size(self,evt): | |
1668 (w,h) = self.GetClientSizeTuple() | |
1669 cols = self.GetNumberCols() | |
1670 col_w = w/(cols+1) | |
1671 self.SetColSize(0,col_w*2) | |
1672 for i in range(1,cols): self.SetColSize(i,col_w) | |
1673 evt.Skip() | |
1674 self.Refresh() | |
1675 | |
1676 class weapon_panel(wx.Panel): | |
1677 def __init__(self, parent, handler): | |
1678 self.hparent = handler #a 1.5012 | |
1679 self.root = getRoot(self) | |
1680 | |
1681 pname = handler.xml.set("name", 'Weapons') | |
1682 | |
1683 wx.Panel.__init__(self, parent, -1) | |
1684 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
1685 sizer = wx.BoxSizer(wx.VERTICAL) | |
1686 sizer.Add(self.grid, 1, wx.EXPAND) | |
1687 | |
1688 sizer2 = wx.BoxSizer(wx.HORIZONTAL) | |
1689 sizer2.Add(wx.Button(self, 10, "Remove Weapon"), 0, wx.EXPAND) | |
1690 sizer2.Add(wx.Size(10,10)) | |
1691 sizer2.Add(wx.Button(self, 20, "Add Weapon"), 0, wx.EXPAND) | |
1692 | |
1693 sizer.Add(sizer2, 0, wx.EXPAND) | |
1694 sizer.Add(wx.StaticText(self, -1, "Right click a weapon's footnote to see what the footnotes mean."),0, wx.EXPAND)#a 1.5012 | |
1695 self.sizer = sizer | |
1696 self.SetSizer(self.sizer) | |
1697 self.SetAutoLayout(True) | |
1698 self.Fit() | |
1699 | |
1700 self.sizer2 = sizer2 | |
1701 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) | |
1702 self.Bind(wx.EVT_BUTTON, self.on_add, id=20) | |
1703 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
1704 self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.on_gridRclick)#a 1.5012 | |
1705 | |
1706 n_list = handler.xml.findall('weapon') | |
1707 self.n_list = n_list | |
1708 self.xml = handler.xml | |
1709 self.handler = handler | |
1710 self.colAttr = ['name','damage','mod','critical','type','weight', | |
1711 'range','size','Total','fn', 'comment'] #a 1.5012 | |
1712 col_names = ['Name','Damage','To hit\nmod','Critical','Type','Weight', | |
1713 'Range','Size','Total','Foot\nnotes','Comment'] #a 1.5012 | |
1714 gridColCount=len(col_names)#a 1.5012 | |
1715 self.grid.CreateGrid(len(n_list),gridColCount,1) #a 1.5012 | |
1716 self.grid.SetRowLabelSize(0) | |
1717 | |
1718 for i in range(gridColCount): self.grid.SetColLabelValue(i,col_names[i]) | |
1719 self.refresh_data() | |
1720 self.temp_dom = None | |
1721 | |
1722 | |
1723 #mark4 | |
1724 #a 1.5012 add entire method. | |
1725 def on_gridRclick(self,evt): | |
1726 row = evt.GetRow() | |
1727 col = evt.GetCol() | |
1728 value = self.grid.GetCellValue(row,col) | |
1729 | |
1730 if col == 9 and value != 'None': | |
1731 n = self.n_list[row] | |
1732 name = n.get('name') | |
1733 handler = self.hparent | |
1734 masterFrame = handler.frame | |
1735 title = name+"'s Special Weapon Characteristics" | |
1736 fnFrame = wx.Frame(masterFrame, -1, title) | |
1737 fnFrame.panel = wx.html.HtmlWindow(fnFrame,-1) | |
1738 if not self.temp_dom: | |
1739 tree = parse(dir_struct["dnd35"]+ "dnd35weapons.xml") | |
1740 self.temp_dom = tree.getroot() | |
1741 f_list = self.temp_dom.findall('f') # the footnotes | |
1742 n = self.n_list[row] | |
1743 name = n.get('name') | |
1744 footnotes = n.get('fn') | |
1745 html_str = "<html><body>" | |
1746 html_str += """<table border='1' width=100% ><tr BGCOLOR=#E9E9E9 > | |
1747 <th width='10%'>Note</th><th>Description</th></tr>\n""" | |
1748 if footnotes == "": | |
1749 html_str += "<tr ALIGN='center'><td></td>" | |
1750 html_str += " <td>This weapon has no footnotes</td></tr>" | |
1751 for i in range(len(footnotes)): | |
1752 aNote=footnotes[i] | |
1753 found=False | |
1754 for f in f_list: | |
1755 if f.get('mark') == aNote: | |
1756 found=True | |
1757 text=f.get('txt') | |
1758 html_str += ("<tr ALIGN='center'><td>"+aNote+"</td>"+ | |
1759 "<td>"+text+"</td></tr>\n") | |
1760 if not found: | |
1761 html_str += ("<tr ALIGN='center'><td>"+aNote+"</td>"+ | |
1762 "<td>is not a recognized footnote</td></tr>\n") | |
1763 | |
1764 html_str += "</table>" | |
1765 html_str += "</body> </html> " | |
1766 fnFrame.panel.SetPage(html_str) | |
1767 fnFrame.Show() | |
1768 return | |
1769 pass | |
1770 | |
1771 | |
1772 def on_cell_change(self,evt): | |
1773 row = evt.GetRow() | |
1774 col = evt.GetCol() | |
1775 value = self.grid.GetCellValue(row,col) | |
1776 if col == 2 and not int(value): # special case for mod, demoted | |
1777 value = "0" #a 5.012 demoted | |
1778 self.n_list[row].set('mod',value) # a 5.012 demoted | |
1779 if not (col == 9 and value == "None" and | |
1780 self.n_list[row].get('fn') == "None" | |
1781 ): #a 5.012 special case for footnotes | |
1782 self.n_list[row].set(self.colAttr[col],value)#a 5.012 | |
1783 | |
1784 | |
1785 def refresh_row(self,i): | |
1786 n = self.n_list[i] | |
1787 fn = n.get('fn') | |
1788 name = n.get('name') | |
1789 mod = n.get('mod') | |
1790 ran = n.get('range') | |
1791 total = str(int(mod) + self.handler.get_mod(ran)) | |
1792 self.grid.SetCellValue(i,0,name) | |
1793 self.grid.SetCellValue(i,1,n.get('damage')) | |
1794 self.grid.SetCellValue(i,2,mod) | |
1795 self.grid.SetCellValue(i,3,n.get('critical')) | |
1796 self.grid.SetCellValue(i,4,n.get('type')) | |
1797 self.grid.SetCellValue(i,5,n.get('weight')) | |
1798 self.grid.SetCellValue(i,6,ran) | |
1799 self.grid.SetCellValue(i,7,n.get('size') ) | |
1800 self.grid.SetCellValue(i,8,total) | |
1801 self.grid.SetCellValue(i,9,safeGetAttr(n,'fn','None')) #a 1.5012 | |
1802 self.grid.SetCellValue(i,10,safeGetAttr(n,'comment','')) #a 1.5012 | |
1803 self.grid.SetReadOnly(i,8) | |
1804 | |
1805 def on_remove(self,evt): #o 1.6011 correcting wrongful deletion | |
1806 rows = self.grid.GetNumberRows() | |
1807 for i in range(rows-1,-1,-1): #a 1.6011 or you lose context | |
1808 if self.grid.IsInSelection(i,0): | |
1809 self.grid.DeleteRows(i) | |
1810 self.xml.remove(self.n_list[i]) | |
1811 self.n_list = self.xml.findall('weapon') | |
1812 self.handler.refresh_weapons() | |
1813 | |
1814 def on_add(self,evt): | |
1815 if not self.temp_dom: | |
1816 tree = parse(dir_struct["dnd35"]+"dnd35weapons.xml") | |
1817 self.temp_dom = tree.getroot() | |
1818 f_list = self.temp_dom.findall('weapon') | |
1819 opts = [] | |
1820 for f in f_list: opts.append(f.get('name')) | |
1821 dlg = wx.SingleChoiceDialog(self,'Choose Weapon','Weapon List',opts) | |
1822 if dlg.ShowModal() == wx.ID_OK: | |
1823 i = dlg.GetSelection() | |
1824 new_node = self.xml.append(f_list[i]) | |
1825 self.grid.AppendRows(1) | |
1826 self.n_list = self.xml.findall('weapon') | |
1827 self.refresh_row(self.grid.GetNumberRows()-1) | |
1828 self.handler.refresh_weapons() | |
1829 dlg.Destroy() | |
1830 | |
1831 def on_size(self,event): | |
1832 s = self.GetClientSizeTuple() | |
1833 self.grid.SetDimensions(0,0,s[0],s[1]-40) | |
1834 self.sizer.SetDimension(0,s[1]-40,s[0],25) | |
1835 self.sizer2.SetDimension(0,s[1]-15,s[0],15) | |
1836 (w,h) = self.grid.GetClientSizeTuple() | |
1837 cols = self.grid.GetNumberCols() | |
1838 col_w = w/(cols+1) | |
1839 self.grid.SetColSize(0,col_w*2) | |
1840 for i in range(1,cols): self.grid.SetColSize(i,col_w) | |
1841 | |
1842 def refresh_data(self): | |
1843 for i in range(len(self.n_list)): self.refresh_row(i) | |
1844 | |
1845 | |
1846 class attack_panel(wx.Panel): | |
1847 def __init__(self, parent, handler): | |
1848 pname = handler.xml.set("name", 'Melee') | |
1849 self.parent = parent #a 1.9001 | |
1850 wx.Panel.__init__(self, parent, -1) | |
1851 self.a_grid = attack_grid(self, handler) | |
1852 self.w_panel = weapon_panel(self, handler) | |
1853 self.sizer = wx.BoxSizer(wx.VERTICAL) | |
1854 self.sizer.Add(self.a_grid, 1, wx.EXPAND) | |
1855 self.sizer.Add(self.w_panel, 2, wx.EXPAND) | |
1856 self.Bind(wx.EVT_SIZE, self.on_size) | |
1857 | |
1858 def on_size(self,event): | |
1859 s = self.GetClientSizeTuple() | |
1860 self.sizer.SetDimension(0,0,s[0],s[1]) | |
1861 | |
1862 def refresh_data(self): | |
1863 self.w_panel.refresh_data() | |
1864 self.a_grid.refresh_data() | |
1865 | |
1866 | |
1867 class dnd35armor(combat_char_child): | |
1868 """ Node Handler for ac. This handler will be | |
1869 created by dnd35char_handler. | |
1870 """ | |
1871 def __init__(self,xml_dom,tree_node,parent): | |
1872 combat_char_child.__init__(self,xml_dom,tree_node,parent) | |
1873 self.hparent = parent #a 1.5002 allow ability to run up tree. | |
1874 self.root = getRoot(self) #a 1.5002 | |
1875 self.root.ac = self #a 1.6009 | |
1876 | |
1877 def get_spell_failure(self): | |
1878 return self.get_total('spellfailure') | |
1879 | |
1880 def get_total_weight(self): | |
1881 return self.get_total('weight') | |
1882 | |
1883 def get_check_pen(self): | |
1884 return self.get_total('checkpenalty') | |
1885 | |
1886 def get_armor_class(self): | |
1887 ac_total = 10 | |
1888 | |
1889 ac_total += self.get_total('bonus') | |
1890 #m 1.5009 change to hardcode dex, was incorrect gv "stat" | |
1891 dex_mod = self.root.abilities.get_mod('Dex')#m 1.5009 hardcode dex | |
1892 max_dex = self.get_max_dex() | |
1893 if dex_mod < max_dex: ac_total += dex_mod | |
1894 else: ac_total += max_dex | |
1895 return ac_total | |
1896 | |
1897 def get_max_dex(self): | |
1898 armor_list = self.xml.findall('armor') | |
1899 dex = 10 | |
1900 for a in armor_list: | |
1901 temp = int(a.get("maxdex")) | |
1902 if temp < dex: dex = temp | |
1903 return dex | |
1904 | |
1905 def get_total(self,attr): | |
1906 armor_list = self.xml.findall('armor') | |
1907 total = 0 | |
1908 for a in armor_list: total += int(a.get(attr)) | |
1909 return total | |
1910 | |
1911 def get_design_panel(self,parent): | |
1912 wnd = outline_panel(parent,self,ac_panel,"Armor") | |
1913 wnd.title = "Armor" | |
1914 return wnd | |
1915 | |
1916 def on_rclick( self, evt ): | |
1917 ac = self.get_armor_class() | |
1918 fac = (int(ac)-(self.root.abilities.get_mod('Dex'))) | |
1919 | |
1920 txt = '((AC: %s Normal, %s Flatfoot))' % ( ac, fac ) #a 1.5002 | |
1921 self.chat.ParsePost( txt, True, True ) | |
1922 | |
1923 def tohtml(self): | |
1924 html_str = """<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > | |
1925 <th>AC</th><th>Check Penalty</th><th >Spell Failure</th> | |
1926 <th>Max Dex</th><th>Total Weight</th></tr>""" | |
1927 html_str += "<tr ALIGN='center' >" | |
1928 html_str += "<td>"+str(self.get_armor_class())+"</td>" | |
1929 html_str += "<td>"+str(self.get_check_pen())+"</td>" | |
1930 html_str += "<td>"+str(self.get_spell_failure())+"</td>" | |
1931 html_str += "<td>"+str(self.get_max_dex())+"</td>" | |
1932 html_str += "<td>"+str(self.get_total_weight())+"</td></tr></table>" | |
1933 n_list = self.xml.getchildren() | |
1934 for n in n_list: | |
1935 html_str += """<P><table width=100% border=1 ><tr BGCOLOR=#E9E9E9 > | |
1936 <th colspan=3>Armor</th><th>Type</th><th >Bonus</th></tr>""" | |
1937 html_str += "<tr ALIGN='center' >" | |
1938 html_str += "<td colspan=3>"+n.get('name')+"</td>" | |
1939 html_str += "<td>"+n.get('type')+"</td>" | |
1940 html_str += "<td>"+n.get('bonus')+"</td></tr>" | |
1941 html_str += """<tr BGCOLOR=#E9E9E9 >""" | |
1942 html_str += "<th>Check Penalty</th><th>Spell Failure</th>" | |
1943 html_str += "<th>Max Dex</th><th>Speed</th><th>Weight</th></tr>" | |
1944 html_str += "<tr ALIGN='center'>" | |
1945 html_str += "<td>"+n.get('checkpenalty')+"</td>" | |
1946 html_str += "<td>"+n.get('spellfailure')+"</td>" | |
1947 html_str += "<td>"+n.get('maxdex')+"</td>" | |
1948 html_str += "<td>"+n.get('speed')+"</td>" | |
1949 html_str += "<td>"+n.get('weight')+"</td></tr></table>" | |
1950 return html_str | |
1951 | |
1952 | |
1953 class ac_panel(wx.Panel): | |
1954 def __init__(self, parent, handler): | |
1955 pname = handler.xml.set("name", 'Armor') | |
1956 self.hparent = handler | |
1957 wx.Panel.__init__(self, parent, -1) | |
1958 self.grid =wx.grid.Grid(self, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS) | |
1959 sizer = wx.BoxSizer(wx.VERTICAL) | |
1960 sizer.Add(self.grid, 1, wx.EXPAND) | |
1961 | |
1962 sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
1963 sizer1.Add(wx.Button(self, 10, "Remove Armor"), 1, wx.EXPAND) | |
1964 sizer1.Add(wx.Size(10,10)) | |
1965 sizer1.Add(wx.Button(self, 20, "Add Armor"), 1, wx.EXPAND) | |
1966 | |
1967 sizer.Add(sizer1, 0, wx.EXPAND) | |
1968 | |
1969 self.sizer = sizer | |
1970 self.SetSizer(self.sizer) | |
1971 self.SetAutoLayout(True) | |
1972 self.Fit() | |
1973 | |
1974 self.Bind(wx.EVT_BUTTON, self.on_remove, id=10) | |
1975 self.Bind(wx.EVT_BUTTON, self.on_add, id=20) | |
1976 self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change) | |
1977 self.xml = handler.xml | |
1978 n_list = handler.xml.getchildren() | |
1979 self.n_list = n_list | |
1980 col_names = ['Armor','bonus','maxdex','cp','sf','weight','speed','type'] | |
1981 self.grid.CreateGrid(len(n_list),len(col_names),1) | |
1982 self.grid.SetRowLabelSize(0) | |
1983 for i in range(len(col_names)): self.grid.SetColLabelValue(i,col_names[i]) | |
1984 self.atts =['name','bonus','maxdex','checkpenalty', | |
1985 'spellfailure','weight','speed','type'] | |
1986 for i in range(len(n_list)): self.refresh_row(i) | |
1987 self.temp_dom = None | |
1988 | |
1989 | |
1990 def on_cell_change(self,evt): | |
1991 row = evt.GetRow() | |
1992 col = evt.GetCol() | |
1993 value = self.grid.GetCellValue(row,col) | |
1994 if col >= 1 and col <= 5: | |
1995 try: | |
1996 int(value) | |
1997 self.n_list[row].set(self.atts[col],value) | |
1998 except: self.grid.SetCellValue(row,col,"0") | |
1999 else: self.n_list[row].set(self.atts[col],value) | |
2000 | |
2001 def refresh_row(self,i): | |
2002 n = self.n_list[i] | |
2003 for y in range(len(self.atts)): self.grid.SetCellValue(i,y,n.get(self.atts[y])) | |
2004 | |
2005 def on_remove(self,evt): | |
2006 rows = self.grid.GetNumberRows() | |
2007 for i in range(rows): | |
2008 if self.grid.IsInSelection(i,0): | |
2009 self.grid.DeleteRows(i) | |
2010 self.xml.remove(self.n_list[i]) | |
2011 | |
2012 def on_add(self,evt): | |
2013 if not self.temp_dom: | |
2014 tree = parse(dir_struct["dnd35"]+"dnd35armor.xml") | |
2015 self.temp_dom = tree.getroot() | |
2016 f_list = self.temp_dom.findall('armor') | |
2017 opts = [] | |
2018 for f in f_list: opts.append(f.get('name')) | |
2019 dlg = wx.SingleChoiceDialog(self,'Choose Armor:','Armor List',opts) | |
2020 if dlg.ShowModal() == wx.ID_OK: | |
2021 i = dlg.GetSelection() | |
2022 new_node = self.xml.append(f_list[i]) | |
2023 self.grid.AppendRows(1) | |
2024 self.refresh_row(self.grid.GetNumberRows()-1) | |
2025 dlg.Destroy() | |
2026 | |
2027 def on_size(self,event): | |
2028 s = self.GetClientSizeTuple() | |
2029 self.grid.SetDimensions(0,0,s[0],s[1]-25) | |
2030 self.sizer.SetDimension(0,s[1]-25,s[0],25) | |
2031 (w,h) = self.grid.GetClientSizeTuple() | |
2032 cols = self.grid.GetNumberCols() | |
2033 col_w = w/(cols+2) | |
2034 self.grid.SetColSize(0,col_w*3) | |
2035 for i in range(1,cols): self.grid.SetColSize(i,col_w) |