comparison orpg/tools/InterParse.py @ 195:b633f4c64aae alpha

Traipse Alpha 'OpenRPG' {100219-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 (Patch-2) New Features: New Namespace method with two new syntaxes Fixes: Fix to Server GUI startup errors Fix to Server GUI Rooms tab updating Fix to Chat and Settings if non existant die roller is picked Fix to Dieroller and .open() used with .vs(). Successes are correctly calculated Fix to Alias Lib's Export to Tree, Open, Save features Fix to alias node, now works properly Fix to Splitter node, minor GUI cleanup
author sirebral
date Sat, 24 Apr 2010 08:37:20 -0500
parents
children 0bc44a57ae6c
comparison
equal deleted inserted replaced
182:4b2884f29a72 195:b633f4c64aae
1 #!/usr/bin/env python
2 # Copyright (C) 2000-2010 The OpenRPG Project
3 #
4 # openrpg-dev@lists.sourceforge.net
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 # --
20 #
21 # File: InterParse.py
22 # Author:
23 # Maintainer: Tyler Starke (Traipse)
24 # Version:
25 # $Id: InterParse.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
26 #
27 # Description: InterParse = Interpretor Parser. This class parses all of the node referencing.
28 #
29
30 from orpg.orpgCore import component
31 import re
32 from orpg.tools.orpg_log import logger
33 from wx import TextEntryDialog, ID_OK
34
35 class InterParse():
36
37 def __init__(self):
38 pass
39
40 def Post(self, s, send=False, myself=False):
41 s = self.Normalize(s)
42 component.get('chat').set_colors()
43 component.get('chat').Post(s, send, myself)
44
45 def ParseLogic(self, s, node):
46 'Nodes now parse through ParsLogic. Easily add new parse rules right here!!'
47 s = self.NameSpaceE(s)
48 s = self.NameSpaceI(s, node)
49 s = self.NodeMap(s, node)
50 s = self.NodeParent(s, node.get('map'))
51 return s
52
53 def Normalize(self, s):
54 for plugin_fname in component.get('chat').activeplugins.keys():
55 plugin = component.get('chat').activeplugins[plugin_fname]
56 try: s = plugin.pre_parse(s)
57 except Exception, e:
58 if str(e) != "'module' object has no attribute 'post_msg'":
59 logger.general(traceback.format_exc())
60 logger.general("EXCEPTION: " + str(e))
61 if component.get('chat').parsed == 0:
62 s = self.NameSpaceE(s)
63 s = self.Node(s)
64 s = self.Dice(s)
65 s = self.Filter(s)
66 component.get('chat').parsed = 1
67 return s
68
69 def Filter(self, s):
70 s = component.get('chat').GetFilteredText(s)
71 return s
72
73 def Node(self, s):
74 """Parses player input for embedded nodes rolls"""
75 cur_loc = 0
76 #[a-zA-Z0-9 _\-\.]
77 reg = re.compile("(!@(.*?)@!)")
78 matches = reg.findall(s)
79 for i in xrange(0,len(matches)):
80 newstr = self.Node(self.resolve_nodes(matches[i][1]))
81 s = s.replace(matches[i][0], newstr, 1)
82 return s
83
84 def Dice(self, s):
85 """Parses player input for embedded dice rolls"""
86 reg = re.compile("\[([^]]*?)\]")
87 matches = reg.findall(s)
88 for i in xrange(0,len(matches)):
89 newstr = self.Unknown(matches[i])
90 qmode = 0
91 newstr1 = newstr
92 if newstr[0].lower() == 'q':
93 newstr = newstr[1:]
94 qmode = 1
95 if newstr[0].lower() == '#':
96 newstr = newstr[1:]
97 qmode = 2
98 try: newstr = component.get('DiceManager').proccessRoll(newstr)
99 except: pass
100 if qmode == 1:
101 s = s.replace("[" + matches[i] + "]",
102 "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
103 elif qmode == 2:
104 s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
105 else: s = s.replace("[" + matches[i] + "]",
106 "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
107 return s
108
109 def Unknown(self, s):
110 # Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY
111 newstr = "0"
112 reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)")
113 matches = reg.findall(s)
114 for i in xrange(0,len(matches)):
115 lb = "Replace '?' with: "
116 if len(matches[i][0]):
117 lb = matches[i][1] + "?: "
118 dlg = TextEntryDialog(component.get('chat'), lb, "Missing Value?")
119 dlg.SetValue('')
120 if matches[i][0] != '':
121 dlg.SetTitle("Enter Value for " + matches[i][1])
122 if dlg.ShowModal() == ID_OK: newstr = dlg.GetValue()
123 if newstr == '': newstr = '0'
124 s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1)
125 dlg.Destroy()
126 return s
127
128 def NameSpaceI(self, s, node):
129 reg = re.compile("(!=(.*?)=!)")
130 matches = reg.findall(s)
131 for i in xrange(0,len(matches)):
132 tree_map = node.get('map').split('::')
133 root = self.get_node(tree_map[0])
134 find = matches[i][1].split('::')
135 names = root.getiterator('nodehandler')
136 for name in names:
137 if find[0] == name.get('name'):
138 if name.get('class') == 'rpg_grid_handler':
139 newstr = self.NameSpaceGrid(find, name); break
140 else: newstr = str(name.find('text').text); break
141 else: newstr = 'Invalid Reference!'
142 s = s.replace(matches[i][0], newstr, 1)
143 s = self.ParseLogic(s, name)
144 return s
145
146 def NameSpaceE(self, s):
147 reg = re.compile("(!&(.*?)&!)")
148 matches = reg.findall(s)
149 for i in xrange(0,len(matches)):
150 find = matches[i][1].split('::')
151 root = find[0]
152 root = self.get_node(root)
153 names = root.getiterator('nodehandler')
154 for name in names:
155 if find[1] == name.get('name'):
156 if name.get('class') == 'rpg_grid_handler':
157 newstr = self.NameSpaceGrid([find[1], find[2]], name); break
158 else: newstr = str(name.find('text').text); break
159 else: newstr = 'Invalid Reference!'
160 s = s.replace(matches[i][0], newstr, 1)
161 s = self.ParseLogic(s, name)
162 return s
163
164 def NameSpaceGrid(self, s, node):
165 cell = tuple(s[1].strip('(').strip(')').split(','))
166 grid = node.find('grid')
167 rows = grid.findall('row')
168 col = rows[int(self.Dice(cell[0]))-1].findall('cell')
169 try: s = self.ParseLogic(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
170 except: s = 'Invalid Grid Reference!'
171 return s
172
173 def NodeMap(self, s, node):
174 """Parses player input for embedded nodes rolls"""
175 cur_loc = 0
176 reg = re.compile("(!!(.*?)!!)")
177 matches = reg.findall(s)
178 for i in xrange(0,len(matches)):
179 tree_map = node.get('map')
180 tree_map = tree_map + '::' + matches[i][1]
181 newstr = '!@'+ tree_map +'@!'
182 s = s.replace(matches[i][0], newstr, 1)
183 s = self.Node(s)
184 s = self.NodeParent(s, tree_map)
185 return s
186
187 def NodeParent(self, s, tree_map):
188 """Parses player input for embedded nodes rolls"""
189 cur_loc = 0
190 reg = re.compile("(!#(.*?)#!)")
191 matches = reg.findall(s)
192 for i in xrange(0,len(matches)):
193 ## Build the new tree_map
194 new_map = tree_map.split('::')
195 del new_map[len(new_map)-1]
196 parent_map = matches[i][1].split('::')
197 ## Backwards Reference the Parent Children
198 child_node = self.get_node('::'.join(new_map))
199 newstr = self.get_root(child_node, tree_map, new_map, parent_map)
200 s = s.replace(matches[i][0], newstr, 1)
201 s = self.Node(s)
202 return s
203
204 def get_root(self, child_node, tree_map, new_map, parent_map):
205 if child_node == 'Invalid Reference!': return child_node
206 roots = child_node.getchildren(); tr = tree_map.split('::')
207 newstr = ''
208 for root in roots:
209 try: t = new_map.index(root.get('name'))
210 except: t = 1
211 if parent_map[0] == root.get('name'):
212 newstr = '!@' + '::'.join(new_map[:len(tr)-t]) + '::' + '::'.join(parent_map) + '@!'
213 if newstr != '': return newstr
214 else:
215 del new_map[len(new_map)-1]
216 child_node = self.get_node('::'.join(new_map))
217 newstr = self.get_root(child_node, tree_map, new_map, parent_map)
218 return newstr
219
220 def get_node(self, s):
221 return_node = 'Invalid Reference!'
222 value = ""
223 path = s.split('::')
224 depth = len(path)
225 try: node = component.get('tree').tree_map[path[0]]['node']
226 except Exception, e: return return_node
227 return_node = self.resolve_get_loop(node, path, 1, depth)
228 return return_node
229
230 def resolve_get_loop(self, node, path, step, depth):
231 if step == depth: return node
232 else:
233 child_list = node.findall('nodehandler')
234 for child in child_list:
235 if step == depth: break
236 if child.get('name') == path[step]:
237 node = self.resolve_get_loop(child, path, step+1, depth)
238 return node
239
240 def resolve_nodes(self, s):
241 self.passed = False
242 string = 'Invalid Reference!'
243 value = ""
244 path = s.split('::')
245 depth = len(path)
246 try: node = component.get('tree').tree_map[path[0]]['node']
247 except Exception, e: return string
248 if node.get('class') in ('dnd35char_handler',
249 "SWd20char_handler",
250 "d20char_handler",
251 "dnd3echar_handler"): string = self.resolve_cust_loop(node, path, 1, depth)
252 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
253 else: string = self.resolve_loop(node, path, 1, depth)
254 return string
255
256 def resolve_loop(self, node, path, step, depth):
257 if step == depth: return self.resolution(node)
258 else:
259 child_list = node.findall('nodehandler')
260 for child in child_list:
261 if step == depth: break
262 if child.get('name') == path[step]:
263 node = child
264 step += 1
265 if node.get('class') in ('dnd35char_handler',
266 "SWd20char_handler",
267 "d20char_handler",
268 "dnd3echar_handler"):
269 string = self.resolve_cust_loop(node, path, step, depth)
270 elif node.get('class') == 'rpg_grid_handler':
271 string = self.resolve_grid(node, path, step, depth)
272 else: string = self.resolve_loop(node, path, step, depth)
273 return string
274
275 def resolution(self, node):
276 if self.passed == False:
277 self.passed = True
278 if node.get('class') == 'textctrl_handler':
279 s = str(node.find('text').text)
280 else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
281 else: s = ''
282 s = self.ParseLogic(s, node)
283 return s
284
285 def resolve_grid(self, node, path, step, depth):
286 if step == depth:
287 return 'Invalid Grid Reference!'
288 cell = tuple(path[step].strip('(').strip(')').split(','))
289 grid = node.find('grid')
290 rows = grid.findall('row')
291 col = rows[int(self.Dice(cell[0]))-1].findall('cell')
292 try: s = self.ParseLogic(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
293 except: s = 'Invalid Grid Reference!'
294 return s
295
296 def resolve_cust_loop(self, node, path, step, depth):
297 s = 'Invalid Reference!'
298 node_class = node.get('class')
299 ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
300 if step == depth: self.resolution(node)
301 ##Build Abilities dictionary##
302 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities')
303 else: ab = node.find('abilities')
304 ab_list = ab.findall('stat'); pc_stats = {}
305
306 for ability in ab_list:
307 pc_stats[ability.get('name')] = (
308 str(ability.get('base')),
309 str((int(ability.get('base'))-10)/2) )
310 pc_stats[ability.get('abbr')] = (
311 str(ability.get('base')),
312 str((int(ability.get('base'))-10)/2) )
313
314 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
315 else: ab = node.find('saves')
316 ab_list = ab.findall('save')
317 for save in ab_list:
318 pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
319 if save.get('name') == 'Fortitude': abbr = 'Fort'
320 if save.get('name') == 'Reflex': abbr = 'Ref'
321 if save.get('name') == 'Will': abbr = 'Will'
322 pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
323
324 if path[step].lower() == 'skill':
325 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
326 node = node.find('skills')
327 child_list = node.findall('skill')
328 for child in child_list:
329 if path[step+1].lower() == child.get('name').lower():
330 if step+2 == depth: s = child.get('rank')
331 elif path[step+2].lower() == 'check':
332 s = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']'
333 return s
334
335 if path[step].lower() == 'feat':
336 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
337 node = node.find('feats')
338 child_list = node.findall('feat')
339 for child in child_list:
340 if path[step+1].lower() == child.get('name').lower():
341 if step+2 == depth: s = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
342 return s
343 if path[step].lower() == 'cast':
344 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snp')
345 node = node.find('spells')
346 child_list = node.findall('spell')
347 for child in child_list:
348 if path[step+1].lower() == child.get('name').lower():
349 if step+2 == depth: s = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
350 return s
351 if path[step].lower() == 'attack':
352 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat')
353 if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm':
354 bonus_text = '(Melee)'
355 bonus = node.find('attacks')
356 bonus = bonus.find('melee')
357 bonus = bonus.attrib; d = int(pc_stats['Str'][1])
358 elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r':
359 bonus_text = '(Ranged)'
360 bonus = node.find('attacks')
361 bonus = bonus.find('ranged')
362 bonus = bonus.attrib; d = int(pc_stats['Dex'][1])
363 for b in bonus:
364 d += int(bonus[b])
365 bonus = str(d)
366 if path[step+2] == None: s= bonus
367 else:
368 weapons = node.find('attacks')
369 weapons = weapons.findall('weapon')
370 for child in weapons:
371 if path[step+2].lower() == child.get('name').lower():
372 s = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']'
373 return s
374 elif pc_stats.has_key(path[step].title()):
375 if step+1 == depth: s = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
376 elif path[step+1].title() == 'Mod': s = pc_stats[path[step].title()][1]
377 elif path[step+1].title() == 'Check': s = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
378 return s
379 return s
380
381 Parse = InterParse()