# HG changeset patch # User sirebral # Date 1276675580 18000 # Node ID 9230a33defd9882b79b7230a48da4b069a25e495 # Parent b29454610f36663dad8506ab3935878e0acddaa6 Traipse Beta 'OpenRPG' {100616-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 (Closing/Closed) New Features: New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order New to Server GUI, can now clear log Updates: Update to Warhammer PC Sheet. Rollers set as macros. Should work with little maintanence. Update to Browser Server window. Display rooms with ' " & cleaner Update to Server. Handles ' " & cleaner. 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 Fix to Single and Double quotes in Whiteboard text Fix to Background images not showing when using the Image Server Fix to Duplicate chat names appearing Fix to Server GUI's logging output Fix to FNB.COLORFUL_TABS bug. diff -r b29454610f36 -r 9230a33defd9 orpg/dieroller/rollers/d20.py --- a/orpg/dieroller/rollers/d20.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/dieroller/rollers/d20.py Wed Jun 16 03:06:20 2010 -0500 @@ -41,19 +41,20 @@ class d20dc(std): def __init__(self,source=[],DC=10,mod=0): std.__init__(self,source) + print "Source", source self.DC = DC self.mod = mod - self.append(static_di(mod)) + #self.append(static_di(mod)) def is_success(self): - return ((self.sum() >= self.DC or self.data[0] == 20) and self.data[0] != 1) + return ((self.sum()+self.mod >= self.DC or self.data[0] == 20) and self.data[0] != 1) def __str__(self): myStr = "[" + str(self.data[0]) for a in self.data[1:]: - myStr += "," + myStr += ", " myStr += str(a) - myStr += "] = (" + str(self.sum()) + ")" + myStr += ", "+str(self.mod)+ "] = (" + str(self.sum()+self.mod) + ")" myStr += " vs DC " + str(self.DC) if self.is_success(): myStr += " Success!" else: myStr += " Failure!" diff -r b29454610f36 -r 9230a33defd9 orpg/dieroller/rollers/std.py --- a/orpg/dieroller/rollers/std.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/dieroller/rollers/std.py Wed Jun 16 03:06:20 2010 -0500 @@ -38,7 +38,7 @@ if self.data[i].lastroll() >= num: self.data[i].extraroll() done = 0 - if done: return self + if done: print self; return self else: return self.open(num) def minroll(self,min): diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/gametree.py --- a/orpg/gametree/gametree.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/gametree.py Wed Jun 16 03:06:20 2010 -0500 @@ -47,7 +47,7 @@ import string, urllib, time, os from shutil import copytree, copystat, copy, copyfile -from orpg.orpg_xml import xml +#from orpg.orpg_xml import xml from orpg.tools.validate import validate from orpg.tools.orpg_log import logger, debug from orpg.tools.orpg_settings import settings diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/nodehandlers/chatmacro.py --- a/orpg/gametree/nodehandlers/chatmacro.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/nodehandlers/chatmacro.py Wed Jun 16 03:06:20 2010 -0500 @@ -42,15 +42,12 @@ def __init__(self,xml,tree_node): node_handler.__init__(self,xml,tree_node) self.xml = xml - self.text_elem = self.xml.find('text') - self.text = self.text_elem.text - def set_text(self,txt): - self.text = txt + def set_text(self, txt): + self.xml.find('text').text = txt def on_use(self,evt): - txt = self.text - actionlist = txt.split("\n") + actionlist = self.xml.find('text').text.split("\n") for line in actionlist: if(line != ""): if line[0] != "/": ## it's not a slash command @@ -65,8 +62,7 @@ def tohtml(self): title = self.xml.get("name") - txt = self.text - txt = string.replace(txt,'\n',"
") + txt = string.replace(self.xml.find('text').text,'\n',"
") return "

"+title+":
"+txt P_TITLE = wx.NewId() @@ -80,7 +76,7 @@ sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Chat Macro"), wx.VERTICAL) self.text = {} self.text[P_TITLE] = wx.TextCtrl(self, P_TITLE, handler.xml.get('name')) - self.text[P_BODY] = wx.TextCtrl(self, P_BODY, handler.text, style=wx.TE_MULTILINE) + self.text[P_BODY] = wx.TextCtrl(self, P_BODY, handler.xml.find('text').text, style=wx.TE_MULTILINE) sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND) sizer.Add(self.text[P_TITLE], 0, wx.EXPAND) sizer.Add(wx.StaticText(self, -1, "Text Body:"), 0, wx.EXPAND) diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/nodehandlers/core.py --- a/orpg/gametree/nodehandlers/core.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/nodehandlers/core.py Wed Jun 16 03:06:20 2010 -0500 @@ -345,6 +345,7 @@ if bad_txt_found: wx.MessageBox("Some non 7-bit ASCII characters found and stripped","Warning!") txt = u_txt + print txt, self.handler, self.handler.xml self.handler.text._set_nodeValue(txt) diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/nodehandlers/forms.py --- a/orpg/gametree/nodehandlers/forms.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/nodehandlers/forms.py Wed Jun 16 03:06:20 2010 -0500 @@ -30,7 +30,7 @@ from containers import * import orpg.minidom as minidom -from orpg.orpg_xml import xml +#from orpg.orpg_xml import xml from wx.lib.scrolledpanel import ScrolledPanel from orpg.tools.settings import settings from orpg.tools.InterParse import Parse diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/nodehandlers/minilib.py --- a/orpg/gametree/nodehandlers/minilib.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/nodehandlers/minilib.py Wed Jun 16 03:06:20 2010 -0500 @@ -37,6 +37,7 @@ import map_miniature_nodehandler import orpg.mapper.map_msg import orpg.minidom as minidom +from orpg.tools.InterParse import Parse # import scriptkit # Constants @@ -44,17 +45,6 @@ FROM_MINILIB_MAP = {'url':'path', 'name':'label', 'unique':None} CORE_ATTRIBUTES = ['name', 'url', 'unique', 'posy', 'posx', 'hide', 'face', 'heading', 'align', 'locked', 'width', 'height'] -ATTRIBUTE_NAME = 'name' -ATTRIBUTE_URL = 'url' -ATTRIBUTE_UNIQUE = 'unique' -ATTRIBUTE_ID = 'id' -ATTRIBUTE_POSX = 'posx' -ATTRIBUTE_POSY = 'posy' - -TAG_MINIATURE = 'miniature' - -COMPONENT_MAP = 'map' -COMPONENT_SESSION = 'session' # # # @@ -100,11 +90,11 @@ """ str = '' str += "" - for mini in self.xml.findall(TAG_MINIATURE): - url = mini.get(ATTRIBUTE_URL) - label = mini.get(ATTRIBUTE_NAME) + for mini in self.xml.findall('miniature'): + url = mini.get('url') + label = mini.get('name') flag = 0 - try: flag = eval( mini.get(ATTRIBUTE_UNIQUE) ) + try: flag = eval( mini.get('unique') ) except: pass show = 'yes' if flag: show = 'no' @@ -133,13 +123,13 @@ for attrib in obj.keys(): key = TO_MINILIB_MAP.get( attrib, attrib ) if key != None: dict[ key ] = obj.get( attrib ) - dict[ ATTRIBUTE_UNIQUE ] = unique + dict[ 'unique' ] = unique self.new_mini( dict ) else: node_handler.on_drop(self, evt) def new_mini( self, data={}, add=1 ): - mini = Element( TAG_MINIATURE ) + mini = Element( 'miniature' ) for key in data.keys(): mini.set( key, data[ key ] ) for key in CORE_ATTRIBUTES: if mini.get( key ) == ('' or None): mini.set( key, '0' ) @@ -154,37 +144,39 @@ def add_leaf( self, mini, icon='gear' ): tree = self.tree icons = tree.icons - key = mini.get( ATTRIBUTE_NAME ) + key = mini.get( 'name' ) self.mydata.append( mini ) def update_leaves( self ): self.mydata = [] - for n in self.xml.findall(TAG_MINIATURE): self.add_leaf( n ) + for n in self.xml.findall('miniature'): self.add_leaf( n ) def on_drag( self, evt ): print 'drag event caught' def send_mini_to_map( self, mini, count=1, addName=True ): if mini == None: return - if mini.get( ATTRIBUTE_URL ) == '' or mini.get( ATTRIBUTE_URL ) == 'http://': - self.chat.ParsePost( self.chat.colorize(self.chat.syscolor, '"%s" is not a valid URL, the mini "%s" will not be added to the map' % ( mini.get( ATTRIBUTE_URL ), mini.get( ATTRIBUTE_NAME ) )) ) + if mini.get( 'url' ) == '' or mini.get( 'url' ) == 'http://': + Parse.Post( self.chat.colorize(self.chat.syscolor, + '"%s" is not a valid URL, the mini "%s" will not be added to the map' % ( + mini.get( 'url' ), mini.get( 'name' ) )) ) return - session = component.get( COMPONENT_SESSION ) + session = component.get( 'session' ) if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER): component.get("chat").InfoPost("You must be either a player or GM to use the miniature Layer") return - map = component.get(COMPONENT_MAP) + canvas = component.get('map') for loop in range( count ): msg = self.get_miniature_XML( mini, addName) msg = str("" + msg + "") - map.new_data( msg ) + canvas.new_data( msg ) session.send( msg ) def get_miniature_XML( self, mini_xml, addName = True ): msg = orpg.mapper.map_msg.mini_msg() - map = component.get( COMPONENT_MAP ) - session = component.get( COMPONENT_SESSION ) - msg.init_prop( ATTRIBUTE_ID, session.get_next_id() ) + canvas = component.get( 'map' ) + session = component.get( 'session' ) + msg.init_prop( 'id', session.get_next_id() ) msg.init_prop('selected', '1')# this will make the mini initially selected for k in mini_xml.keys(): # translate our attributes to map attributes @@ -193,24 +185,24 @@ if not addName and k == 'name': pass else: msg.init_prop( key, mini_xml.get( k ) ) unique = self.is_unique( mini_xml ) - if addName: label = mini_xml.get( ATTRIBUTE_NAME ) + if addName: label = mini_xml.get( 'name' ) else: label = '' return msg.get_all_xml() def is_unique( self, mini ): - unique = mini.get( ATTRIBUTE_UNIQUE ) + unique = mini.get( 'unique' ) val = 0 try: val = eval( unique ) except: val = len( unique ) return val def sanity_check_nodes( self ): - for node in self.xml.findall(TAG_MINIATURE): - if node.get( ATTRIBUTE_POSX ) == '': node.set( ATTRIBUTE_POSX, '0' ) - if node.get( ATTRIBUTE_POSY ) == '': node.set( ATTRIBUTE_POSY, '0' ) + for node in self.xml.findall('miniature'): + if node.get( 'posx' ) == '': node.set( 'posx', '0' ) + if node.get( 'posy' ) == '': node.set( 'posy', '0' ) def get_mini( self, index ): - try: return self.xml.findall(TAG_MINIATURE)[index] + try: return self.xml.findall('miniature')[index] except: return None class mini_handler( node_handler ): @@ -279,7 +271,7 @@ """Returns a dictionary of label => game tree miniature DOM node mappings. """ self.list = [] - for mini in self.handler.xml.findall(TAG_MINIATURE): self.list.append( mini.get( ATTRIBUTE_NAME ) ) + for mini in self.handler.xml.findall('miniature'): self.list.append( mini.get( 'name' ) ) return self.list def on_close(self, evt): @@ -407,7 +399,7 @@ self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.select_cell) def update_cols( self ): - for n in self.handler.xml.findall(TAG_MINIATURE): + for n in self.handler.xml.findall('miniature'): for k in n.keys(): if k not in self.keys: self.keys.append( k ) @@ -426,7 +418,7 @@ """Returns the list of 'miniature' DOM elements associated with this miniature library. """ - return self.handler.xml.findall( TAG_MINIATURE ) + return self.handler.xml.findall( 'miniature' ) def add_row( self, count = 1 ): """creates a new miniature node, and then adds it to the current @@ -434,8 +426,8 @@ """ self.AppendRows( count ) node = self.handler.new_mini( { - ATTRIBUTE_NAME :' ', - ATTRIBUTE_URL :'http://'} )# minidom.Element( TAG_MINIATURE ) + 'name' :' ', + 'url' :'http://'} )# minidom.Element( 'miniature' ) self.update_all() #self.handler.xml.append( node ) @@ -446,7 +438,7 @@ """ if self.selectedRow > -1: pos = self.selectedRow - list = self.handler.xml.findall(TAG_MINIATURE) + list = self.handler.xml.findall('miniature') self.handler.xml.remove( list[pos] ) self.DeleteRows( pos, 1 ) @@ -492,7 +484,7 @@ return self.GetTable().GetValue( self.selectedRow, 1 ) def getSelectedSerial( self ): - """Returns the ATTRIBUTE_UNIQUE value for the selected row + """Returns the 'unique' value for the selected row """ return self.GetTable().GetValue( self.selectedRow, 2 ) diff -r b29454610f36 -r 9230a33defd9 orpg/gametree/nodehandlers/voxchat.py --- a/orpg/gametree/nodehandlers/voxchat.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/gametree/nodehandlers/voxchat.py Wed Jun 16 03:06:20 2010 -0500 @@ -31,7 +31,6 @@ import re, os, string, core from orpg.orpg_windows import * -import core import orpg.tools.scriptkit import orpg.tools.predTextCtrl import orpg.tools.rgbhex diff -r b29454610f36 -r 9230a33defd9 orpg/main.py --- a/orpg/main.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/main.py Wed Jun 16 03:06:20 2010 -0500 @@ -63,7 +63,7 @@ from xml.etree.ElementTree import ElementTree, Element, parse from xml.etree.ElementTree import fromstring, tostring -from orpg.orpg_xml import xml #to be replaced by etree +#from orpg.orpg_xml import xml #to be replaced by etree #################################### @@ -162,6 +162,11 @@ settings.add('Tip of the Day', 'tipotday_enabled', '1', '0|1', 'Show Tip of the Day on startup') logger.info('New Settings added', True) self.TraipseSuiteWarn('debug') + if setting == 'Meta Servers': + settings.add('Networking', 'MetaServers', 'metaservers.xml', '.xml file', 'Contains a list of Meta Servers') + logger.info('New Settings added', True) + self.validate.config_file("metaservers.xml","default_metaservers.xml") + self.TraipseSuiteWarn('debug') def get_activeplugins(self): try: tmp = self.pluginsFrame.get_activeplugins() @@ -202,7 +207,7 @@ [' -'], [' Tab Styles'], [' Slanted'], - [' Colorful', "check"], + #[' Colorful', "check"], [' Black and White', "check"], [' Aqua', "check"], [' Custom', "check"], @@ -252,7 +257,8 @@ self.mainmenu.SetMenuState('ToolsPasswordManager', True if settings.get('PWMannager') == 'On' else False) tabtheme = settings.get('TabTheme') #This change is stable. TaS. - self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') + if tabtheme == 'slanted&colorful': tabtheme = 'customflat'; settings.change('TabTheme', 'customflat') + #self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", tabtheme == 'slanted&bw') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedAqua", tabtheme == 'slanted&aqua') self.mainmenu.SetMenuState("OpenRPGTabStylesFlatBlackandWhite", tabtheme == 'flat&bw') @@ -318,9 +324,8 @@ #Tab Styles Menus def SetTabStyles(self, *args, **kwargs): - tabtheme = settings.get('TabTheme') #This change is stable. TaS. - self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') + #self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", tabtheme == 'slanted&colorful') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", tabtheme == 'slanted&bw') self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedAqua", tabtheme == 'slanted&aqua') self.mainmenu.SetMenuState("OpenRPGTabStylesFlatBlackandWhite", tabtheme == 'flat&bw') @@ -336,7 +341,6 @@ else: try: menu = args[0] except: logger.general('Invalid Syntax for orpgFrame->SetTabStyles(self, *args, **kwargs)'); return - if kwargs.has_key('graidentTo'): graidentTo = kwargs['graidentTo'] else: graidentTo = None if kwargs.has_key('graidentFrom'): graidentFrom = kwargs['graidentFrom'] @@ -360,7 +364,7 @@ for wnd in tabbedwindows: style = wnd.GetWindowStyleFlag() # remove old tabs style - mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_COLORFUL_TABS) + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS ) style &= mirror style |= newstyle wnd.SetWindowStyleFlag(style) @@ -747,11 +751,11 @@ def do_tab_window(self, xml_dom, parent_wnd): # if container window loop through childern and do a recursive call - temp_wnd = orpgTabberWnd(parent_wnd, style=FNB.FNB_ALLOW_FOREIGN_DND) + temp_wnd = orpgTabberWnd(parent_wnd) children = xml_dom.getchildren() for c in children: - wnd = self.build_window(c,temp_wnd) + wnd = self.build_window(c, temp_wnd) name = c.get("name") temp_wnd.AddPage(wnd, name, False) return temp_wnd @@ -931,12 +935,15 @@ except: etreeEl.text = data display_name = self.chat.chat_display_name(player) - if etreeEl.text:self.chat.Post(display_name+etreeEl.text) + if etreeEl.text: + if "is creating room" in etreeEl.text: self.chat.Post(etreeEl.text) + else: self.chat.Post(display_name+etreeEl.text) for child in etreeEl.getchildren(): if child.tag == 'tree': - dlg = wx.MessageDialog(None, component.strip_html(display_name) + ' is trying to send you a tree node. Accept?', 'Question', - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + dlg = wx.MessageDialog(None, + component.strip_html(display_name) + ' is trying to send you a tree node. Accept?', + 'Question', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: dlg.Destroy() self.tree.on_receive_data(tostring(child)) @@ -1124,7 +1131,7 @@ def OnInit(self): component.add('log', logger) - component.add('xml', xml) + #component.add('xml', xml) component.add('settings', settings) component.add('validate', validate) component.add("tabbedWindows", []) diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/background.py --- a/orpg/mapper/background.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/background.py Wed Jun 16 03:06:20 2010 -0500 @@ -211,28 +211,31 @@ else: return '' def layerTakeDOM(self, xml_dom): - type = BG_COLOR - color = xml_dom.getAttribute("color") - logger.debug("color=" + color) - path = urllib.unquote(xml_dom.getAttribute("path")) - logger.debug("path=" + path) - # Begin ted's map changes - if xml_dom.hasAttribute("color"): - r,g,b = self.r_h.rgb_tuple(xml_dom.getAttribute("color")) + bg_type = xml_dom.get("type") + urlpath = xml_dom.get('path') + color = xml_dom.get("color") + + if urlpath != None: + path = urllib.unquote(xml_dom.get("path")) + logger.debug("path=" + path) + + if color != None: + logger.debug("color=" + color) + r,g,b = self.r_h.rgb_tuple(color) self.set_color(cmpColour(r,g,b)) - # End ted's map changes - if xml_dom.hasAttribute("type"): - type = int(xml_dom.getAttribute("type")) - logger.debug("type=" + str(type)) - if type == BG_TEXTURE: + + if bg_type != None: + logger.debug("type=" + bg_type) + bg_type = int(xml_dom.get("type")) + if bg_type == BG_TEXTURE: if path != "": self.set_texture(path) - elif type == BG_IMAGE: + elif bg_type == BG_IMAGE: if path != "": self.set_image(path, 1) - elif type == BG_NONE: self.clear() - if xml_dom.hasAttribute('local') and xml_dom.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(xml_dom.getAttribute('localPath'))): - self.localPath = urllib.unquote(xml_dom.getAttribute('localPath')) + elif bg_type == BG_NONE: self.clear() + if xml_dom.get('local') == 'True' and os.path.exists(urllib.unquote(xml_dom.get('localPath'))): + self.localPath = urllib.unquote(xml_dom.get('localPath')) self.local = True - self.localTime = int(xml_dom.getAttribute('localTime')) + self.localTime = int(xml_dom.get('localTime')) if self.localTime-time.time() <= 144000: file = open(self.localPath, "rb") imgdata = file.read() diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/background_handler.py --- a/orpg/mapper/background_handler.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/background_handler.py Wed Jun 16 03:06:20 2010 -0500 @@ -83,7 +83,7 @@ postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype}) if self.settings.get_setting('LocalorRemote') == 'Remote': - thread.start_new_thread(self.canvas.layers['bg'].upload, + thread.start_new_thread(self.upload, (postdata, dlg.GetPath(), self.bg_type.GetStringSelection())) else: try: min_url = component.get("cherrypy") + filename @@ -97,6 +97,13 @@ self.canvas.send_map_data() self.canvas.Refresh(False) + def upload(self, postdata, filename, imgtype): + self.canvas.layers['bg'].upload(postdata, filename, imgtype) + self.update_info() + self.canvas.send_map_data() + self.canvas.Refresh(False) + return + def update_info(self): bg_type = self.canvas.layers['bg'].get_type() session=self.canvas.frame.session diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/base_msg.py --- a/orpg/mapper/base_msg.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/base_msg.py Wed Jun 16 03:06:20 2010 -0500 @@ -29,7 +29,7 @@ from threading import RLock from orpg.networking.mplay_client import * -from xml.etree.ElementTree import ElementTree, Element +from xml.etree.ElementTree import ElementTree, Element, fromstring class map_element_msg_base: # This is a base class @@ -216,20 +216,24 @@ self._from_dom(xml_dom,self.set_prop) def init_from_xml(self,xml): - xml_dom = parseXml(xml) - node_list = xml_dom.getElementsByTagName(self.tagname) + #xml_dom = parseXml(xml) + xml_dom = fromstring(xml) + #node_list = xml_dom.getElementsByTagName(self.tagname) + node_list = xml_dom.findall(self.tagname) if len(node_list) < 1: print "Warning: no <" + self.tagname + "/> elements found in DOM." else: while len(node_list): self.init_from_dom(node_list.pop()) - if xml_dom: xml_dom.unlink() + #if xml_dom: xml_dom.unlink() def set_from_xml(self,xml): - xml_dom = parseXml(xml) - node_list = xml_dom.getElementsByTagName(self.tagname) + #xml_dom = parseXml(xml) + xml_dom = fromstring(xml) + #node_list = xml_dom.getElementsByTagName(self.tagname) + node_list = xml_dom.findall(self.tagname) if len(node_list) < 1: print "Warning: no <" + self.tagname + "/> elements found in DOM." else: while len(node_list): self.set_from_dom(node_list.pop()) - if xml_dom: xml_dom.unlink() + #if xml_dom: xml_dom.unlink() # XML importers end ######################################### diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/fog.py --- a/orpg/mapper/fog.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/fog.py Wed Jun 16 03:06:20 2010 -0500 @@ -27,7 +27,7 @@ from base import * from random import Random from region import * -from orpg.minidom import Element +from xml.etree.ElementTree import Element, tostring import traceback COURSE = 10 @@ -47,8 +47,8 @@ for pairs in string.split( points, ';' ): pair = string.split( pairs, ',' ) p = Element( "point" ) - p.setAttribute( "x", pair[0] ) - p.setAttribute( "y", pair[1] ) + p.set( "x", pair[0] ) + p.set( "y", pair[1] ) result.append( p ) return result @@ -59,23 +59,20 @@ localOutline = "points" elem = Element( "poly" ) if action == "del": - elem.setAttribute( "action", action ) - elem.setAttribute( "outline", localOutline ) + elem.set( "action", action ) + elem.set( "outline", localOutline ) if localOutline == 'points': - list = self.points_to_elements( self.outline ) - for p in list: elem.appendChild( p ) - str = elem.toxml() - elem.unlink() - return str - elem.setAttribute( "action", action ) + foglist = self.points_to_elements( self.outline ) + for p in foglist: elem.append( p ) + return tostring(elem) + elem.set( "action", action ) if localOutline != None: - elem.setAttribute( "outline", localOutline ) + elem.set( "outline", localOutline ) if localOutline == 'points': - list = self.points_to_elements( self.outline ) - for p in list: elem.appendChild( p ) - xml_str = elem.toxml() - elem.unlink() - return xml_str + foglist = self.points_to_elements( self.outline ) + for p in foglist: elem.append( p ) + #xml_str = elem.toxml() + return tostring(elem) class fog_layer(layer_base): def __init__(self, canvas): @@ -223,11 +220,12 @@ if not self.use_fog: self.use_fog = True self.recompute_fog() - if xml_dom.hasAttribute('serial'): self.serial_number = int(xml_dom.getAttribute('serial')) - children = xml_dom._get_childNodes() + serial = xml_dom.get('serial') + if serial != None: self.serial_number = int(serial) + children = xml_dom.getchildren() for l in children: - action = l.getAttribute("action") - outline = l.getAttribute("outline") + action = l.get("action") + outline = l.get("outline") if (outline == "all"): polyline = [IPoint().make(0,0), IPoint().make(self.width-1, 0), IPoint().make(self.width-1, self.height-1), @@ -240,10 +238,10 @@ polyline = [] lastx = None lasty = None - list = l._get_childNodes() + list = l.getchildren() for point in list: - x = point.getAttribute( "x" ) - y = point.getAttribute( "y" ) + x = point.get( "x" ) + y = point.get( "y" ) if (x != lastx or y != lasty): polyline.append(IPoint().make(int(x), int(y))) lastx = x diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/fog_msg.py --- a/orpg/mapper/fog_msg.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/fog_msg.py Wed Jun 16 03:06:20 2010 -0500 @@ -27,7 +27,7 @@ from base_msg import * from region import * -from orpg.minidom import Element +from xml.etree.ElementTree import Element, tostring import string class fog_msg(map_element_msg_base): @@ -41,19 +41,17 @@ def get_line(self,outline,action,output_act): elem = Element( "poly" ) - if ( output_act ): elem.setAttribute( "action", action ) - if ( outline == 'all' ) or ( outline == 'none' ): elem.setAttribute( "outline", outline ) + if ( output_act ): elem.set( "action", action ) + if ( outline == 'all' ) or ( outline == 'none' ): elem.set( "outline", outline ) else: - elem.setAttribute( "outline", "points" ) + elem.set( "outline", "points" ) for pair in string.split( outline, ";" ): p = string.split( pair, "," ) point = Element( "point" ) - point.setAttribute( "x", p[ 0 ] ) - point.setAttribute( "y", p[ 1 ] ) - elem.appendChild( point ) - str = elem.toxml() - elem.unlink() - return str + point.set( "x", p[ 0 ] ) + point.set( "y", p[ 1 ] ) + elem.append( point ) + return tostring(elem) # convenience method to use if only this line is modified # outputs a element containing only the changes to this line @@ -83,23 +81,18 @@ str(x2)+","+str(y1)+";"+ str(x2)+","+str(y2)+";"+ str(x1)+","+str(y2),action,output_action) - s = "2): if action=="del": self.fogregion.FromPolygon(polyline,0) else: self.fogregion.FromPolygon(polyline,1) diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/grid.py --- a/orpg/mapper/grid.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/grid.py Wed Jun 16 03:06:20 2010 -0500 @@ -406,19 +406,20 @@ else: return '' def layerTakeDOM(self, xml_dom): - if xml_dom.hasAttribute("color"): - r,g,b = self.r_h.rgb_tuple(xml_dom.getAttribute("color")) + color = xml_dom.get('color') + if color != None: + r,g,b = self.r_h.rgb_tuple(color) self.set_color(cmpColour(r,g,b)) #backwards compatible with non-isometric map formated clients - ratio = RATIO_DEFAULT - if xml_dom.hasAttribute("ratio"): ratio = xml_dom.getAttribute("ratio") - if xml_dom.hasAttribute("mode"): - self.SetMode(int(xml_dom.getAttribute("mode"))) - if xml_dom.hasAttribute("size"): - self.unit_size = int(xml_dom.getAttribute("size")) + ratio = RATIO_DEFAULT if xml_dom.get("ratio") == None else xml_dom.get('ratio') + mode = xml_dom.get('mode') + if mode != None: self.SetMode(int(mode)) + size = xml_dom.get('size') + if size != None: + self.unit_size = int(size) self.unit_size_y = self.unit_size - if xml_dom.hasAttribute("snap"): - if (xml_dom.getAttribute("snap") == 'True') or (xml_dom.getAttribute("snap") == "1"): self.snap = True - else: self.snap = False - if xml_dom.hasAttribute("line"): - self.SetLine(int(xml_dom.getAttribute("line"))) + if (xml_dom.get("snap") == 'True') or (xml_dom.get("snap") == "1"): self.snap = True + else: self.snap = False + line = xml_dom.get('line') + if line != None: self.SetLine(int(line)) + diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/map.py --- a/orpg/mapper/map.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/map.py Wed Jun 16 03:06:20 2010 -0500 @@ -45,6 +45,8 @@ from images import ImageHandler from orpg.orpgCore import component from orpg.tools.orpg_settings import settings +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring # Various marker modes for player tools on the map MARKER_MODE_NONE = 0 @@ -259,21 +261,26 @@ dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1) dc.SetDeviceOrigin(-topleft[0], -topleft[1]) dc.SetUserScale(scale, scale) + + layer_order = [] + for i in xrange (0, len(self.parent.layer_handlers)-1): + if self.parent.layer_tabs.GetPageText(i) in ('Background', 'Fog', 'General'): pass + else: layer_order.append(self.parent.layer_tabs.GetPageText(i)) self.layers['bg'].layerDraw(dc, scale, topleft, clientsize) - self.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], - [clientsize[0]/scale, clientsize[1]/scale]) - self.layers['miniatures'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], - [clientsize[0]/scale, clientsize[1]/scale]) - self.layers['whiteboard'].layerDraw(dc) + + for layer in layer_order: + if layer == 'Grid': self.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], + [clientsize[0]/scale, clientsize[1]/scale]) + if layer == 'Miniatures': self.layers['miniatures'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], + [clientsize[0]/scale, clientsize[1]/scale]) + if layer == 'Whiteboard': self.layers['whiteboard'].layerDraw(dc) + self.layers['fog'].layerDraw(dc, topleft, clientsize) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) - - dc.SelectObject(wx.NullBitmap) - del dc + dc.SelectObject(wx.NullBitmap); del dc wdc = self.preppaint() wdc.DrawBitmap(bmp, topleft[0], topleft[1]) - if settings.get_setting("AlwaysShowMapScale") == "1": self.showmapscale(wdc) try: evt.Skip() @@ -622,15 +629,16 @@ --Snowdog 5/27/03 """ try: - #parse the map DOM - xml_dom = parseXml(xml) + xml_dom = fromstring(xml) if xml_dom == None: return - node_list = xml_dom.getElementsByTagName("map") + node_list = xml_dom.findall("map") + if len(node_list) < 1: + if xml_dom.tag == 'map': node_list = [xml_dom] if len(node_list) < 1: pass else: # set map version to incoming data so layers can convert - self.map_version = node_list[0].getAttribute("version") - action = node_list[0].getAttribute("action") + self.map_version = node_list[0].get("version") + action = node_list[0].get("action") if action == "new": self.layers = {} try: self.layers['bg'] = layer_back_ground(self) @@ -643,37 +651,38 @@ except: pass try: self.layers['fog'] = fog_layer(self) except: pass - sizex = node_list[0].getAttribute("sizex") + sizex = node_list[0].get("sizex") or '' if sizex != "": sizex = int(float(sizex)) sizey = self.size[1] self.set_size((sizex,sizey)) self.size_changed = 0 - sizey = node_list[0].getAttribute("sizey") + sizey = node_list[0].get("sizey") or '' if sizey != "": sizey = int(float(sizey)) sizex = self.size[0] self.set_size((sizex,sizey)) self.size_changed = 0 - children = node_list[0]._get_childNodes() + children = node_list[0].getchildren() #fog layer must be computed first, so that no data is inadvertently revealed for c in children: - name = c._get_nodeName() + name = c.tag if name == "fog": self.layers[name].layerTakeDOM(c) for c in children: - name = c._get_nodeName() + name = c.tag if name != "fog": self.layers[name].layerTakeDOM(c) # all map data should be converted, set map version to current version self.map_version = MAP_VERSION - self.Refresh(False) - xml_dom.unlink() # eliminate circular refs + self.Refresh(True) except: pass def re_ids_in_xml(self, xml): + exception = "\nDeprecated call to: Function re_ids_in_xml, line 679, map.py\nThis can mangle XML, please report!" + logger.exception(exception) new_xml = "" tmp_map = map_msg() - xml_dom = parseXml(str(xml)) - node_list = xml_dom.getElementsByTagName("map") + xml_dom = fromstring(xml) + node_list = xml_dom.findall("map") if len(node_list) < 1: pass else: tmp_map.init_from_dom(node_list[0]) @@ -701,8 +710,7 @@ elif l.tagname == 'circle': id = 'circle-' + self.frame.session.get_next_id() l.init_prop("id", id) new_xml = tmp_map.get_all_xml() - if xml_dom: xml_dom.unlink() - return str(new_xml) + return new_xml class map_wnd(wx.Panel): def __init__(self, parent, id): @@ -714,20 +722,23 @@ self.root_dir = os.getcwd() self.current_layer = 2 self.layer_tabs = orpgTabberWnd(self, style=FNB.FNB_NO_X_BUTTON|FNB.FNB_BOTTOM|FNB.FNB_NO_NAV_BUTTONS) + self.layer_handlers = [] - self.layer_handlers.append(background_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[0],"Background") - self.layer_handlers.append(grid_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[1],"Grid") - self.layer_handlers.append(miniatures_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[2],"Miniatures", True) - self.layer_handlers.append(whiteboard_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[3],"Whiteboard") - self.layer_handlers.append(fog_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[4],"Fog") - self.layer_handlers.append(map_handler(self.layer_tabs,-1,self.canvas)) - self.layer_tabs.AddPage(self.layer_handlers[5],"General") + self.layer_handlers.append(background_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[0], "Background") + self.layer_handlers.append(grid_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[1], "Grid") + self.layer_handlers.append(miniatures_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[2], "Miniatures", True) + self.layer_handlers.append(whiteboard_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[3], "Whiteboard") + self.layer_handlers.append(fog_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[4], "Fog") + self.layer_handlers.append(map_handler(self.layer_tabs, -1, self.canvas)) + self.layer_tabs.AddPage(self.layer_handlers[5], "General") self.layer_tabs.SetSelection(2) + + self.layer_order = {1: 'grid', 2: 'miniatures', 3: 'whiteboard'} self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.sizer.Add(self.layer_tabs, 0, wx.EXPAND) @@ -778,9 +789,9 @@ d = wx.FileDialog(self.GetParent(), "Select a file", dir_struct["user"], "", "*.xml", wx.OPEN) if d.ShowModal() == wx.ID_OK: f = open(d.GetPath()) - map_string = f.read() - new_xml = self.canvas.re_ids_in_xml(map_string) - if new_xml: + new_xml = f.read() + f.close() + if new_xml != None: self.canvas.takexml(new_xml) self.canvas.send_map_data("new") self.update_tools() diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/map_msg.py --- a/orpg/mapper/map_msg.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/map_msg.py Wed Jun 16 03:06:20 2010 -0500 @@ -53,17 +53,17 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: + if xml_dom.tag == self.tagname: # If this is a map message, look for the "action=new" # Notice we only do this when the root is a map tag - if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new": + if self.tagname == "map" and xml_dom.get("action") == "new": self.clear() # Process all of the properties in each tag - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): - self.init_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - name = c._get_nodeName() + if xml_dom.keys(): + for k in xml_dom.keys(): + self.init_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + name = c.tag if not self.children.has_key(name): if name == "miniatures": self.children[name] = minis_msg(self.p_lock) elif name == "grid": self.children[name] = grid_msg(self.p_lock) @@ -84,16 +84,16 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: + if xml_dom.tag == self.tagname: # If this is a map message, look for the "action=new" # Notice we only do this when the root is a map tag - if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new": + if self.tagname == "map" and xml_dom.get("action") == "new": self.clear() # Process all of the properties in each tag - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - name = c._get_nodeName() + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + name = c.tag if not self.children.has_key(name): if name == "miniatures": self.children[name] = minis_msg(self.p_lock) elif name == "grid": self.children[name] = grid_msg(self.p_lock) diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/miniatures.py --- a/orpg/mapper/miniatures.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/miniatures.py Wed Jun 16 03:06:20 2010 -0500 @@ -344,27 +344,27 @@ else: return '' def takedom(self, xml_dom): - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("posx"): self.pos.x = int(xml_dom.getAttribute("posx")) - if xml_dom.hasAttribute("posy"): self.pos.y = int(xml_dom.getAttribute("posy")) - if xml_dom.hasAttribute("heading"): self.heading = int(xml_dom.getAttribute("heading")) - if xml_dom.hasAttribute("face"): self.face = int(xml_dom.getAttribute("face")) - if xml_dom.hasAttribute("path"): - self.path = urllib.unquote(xml_dom.getAttribute("path")) + self.id = xml_dom.get("id") + if xml_dom.get("posx") != None: self.pos.x = int(xml_dom.get("posx")) + if xml_dom.get("posy") != None: self.pos.y = int(xml_dom.get("posy")) + if xml_dom.get("heading") != None: self.heading = int(xml_dom.get("heading")) + if xml_dom.get("face") != None: self.face = int(xml_dom.get("face")) + if xml_dom.get("path") != None: + self.path = urllib.unquote(xml_dom.get("path")) self.set_bmp(ImageHandler.load(self.path, 'miniature', self.id)) - if xml_dom.hasAttribute("locked"): - if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True': self.locked = True + if xml_dom.get("locked") != None: + if xml_dom.get("locked") == '1' or xml_dom.get("locked") == 'True': self.locked = True else: self.locked = False - if xml_dom.hasAttribute("hide"): - if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True': self.hide = True + if xml_dom.get("hide") != None: + if xml_dom.get("hide") == '1' or xml_dom.get("hide") == 'True': self.hide = True else: self.hide = False - if xml_dom.hasAttribute("label"): self.label = xml_dom.getAttribute("label") - if xml_dom.hasAttribute("zorder"): self.zorder = int(xml_dom.getAttribute("zorder")) - if xml_dom.hasAttribute("align"): - if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True': self.snap_to_align = 1 + if xml_dom.get("label") != None: self.label = xml_dom.get("label") + if xml_dom.get("zorder") != None: self.zorder = int(xml_dom.get("zorder")) + if xml_dom.get("align") != None: + if xml_dom.get("align") == '1' or xml_dom.get("align") == 'True': self.snap_to_align = 1 else: self.snap_to_align = 0 - if xml_dom.hasAttribute("width"): self.width = int(xml_dom.getAttribute("width")) - if xml_dom.hasAttribute("height"): self.height = int(xml_dom.getAttribute("height")) + if xml_dom.get("width") != None: self.width = int(xml_dom.get("width")) + if xml_dom.get("height") != None: self.height = int(xml_dom.get("height")) ##----------------------------- ## miniature layer @@ -489,36 +489,36 @@ else: return "" def layerTakeDOM(self, xml_dom): - if xml_dom.hasAttribute('serial'): - self.serial_number = int(xml_dom.getAttribute('serial')) - children = xml_dom._get_childNodes() + if xml_dom.get('serial') != None: + self.serial_number = int(xml_dom.get('serial')) + children = xml_dom.getchildren() for c in children: - action = c.getAttribute("action") - id = c.getAttribute('id') + action = c.get("action") + id = c.get('id') if action == "del": mini = self.get_miniature_by_id(id) if mini: self.miniatures.remove(mini); del mini elif action == "new": - pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy'))) - path = urllib.unquote(c.getAttribute('path')) - label = c.getAttribute('label') + pos = cmpPoint(int(c.get('posx')),int(c.get('posy'))) + path = urllib.unquote(c.get('path')) + label = c.get('label') height = width = heading = face = snap_to_align = zorder = 0 locked = hide = False - if c.hasAttribute('height'): height = int(c.getAttribute('height')) - if c.hasAttribute('width'): width = int(c.getAttribute('width')) - if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1': locked = True - if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1': hide = True - if c.getAttribute('heading'): heading = int(c.getAttribute('heading')) - if c.hasAttribute('face'): face = int(c.getAttribute('face')) - if c.hasAttribute('align'): snap_to_align = int(c.getAttribute('align')) - if c.getAttribute('zorder'): zorder = int(c.getAttribute('zorder')) + if c.get('height') != None: height = int(c.get('height')) + if c.get('width') != None: width = int(c.get('width')) + if c.get('locked') == 'True' or c.get('locked') == '1': locked = True + if c.get('hide') == 'True' or c.get('hide') == '1': hide = True + if c.get('heading') != None: heading = int(c.get('heading')) + if c.get('face') != None: face = int(c.get('face')) + if c.get('align') != None: snap_to_align = int(c.get('align')) + if c.get('zorder') != None: zorder = int(c.get('zorder')) min = BmpMiniature(id, path, ImageHandler.load(path, 'miniature', id), pos, heading, face, label, locked, hide, snap_to_align, zorder, width, height) self.miniatures.append(min) - if c.hasAttribute('local') and c.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(c.getAttribute('localPath'))): - localPath = urllib.unquote(c.getAttribute('localPath')) + if c.get('local') == 'True' and os.path.exists(urllib.unquote(c.get('localPath'))): + localPath = urllib.unquote(c.get('localPath')) local = True - localTime = float(c.getAttribute('localTime')) + localTime = float(c.get('localTime')) if localTime-time.time() <= 144000: file = open(localPath, "rb") imgdata = file.read() diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/miniatures_msg.py --- a/orpg/mapper/miniatures_msg.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/miniatures_msg.py Wed Jun 16 03:06:20 2010 -0500 @@ -79,11 +79,11 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.init_prop(k,xml_dom.getAttribute(k)) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.init_prop(k,xml_dom.get(k)) - for c in xml_dom._get_childNodes(): + for c in xml_dom.getchildren(): mini = mini_msg(self.p_lock) try: mini.init_from_dom(c) except Exception, e: print e; continue @@ -103,10 +103,10 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): mini = mini_msg(self.p_lock) try: mini.set_from_dom(c) except Exception, e: print e; continue diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/whiteboard.py --- a/orpg/mapper/whiteboard.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/whiteboard.py Wed Jun 16 03:06:20 2010 -0500 @@ -46,7 +46,7 @@ self.scale = 1 self.r_h = RGBHex() self.selected = False - self.text_string = text_string + self.text_string = text_string.replace('"', '"').replace("'", ''') self.id = id self.weight = int(weight) self.pointsize = int(pointsize) @@ -95,7 +95,8 @@ # Draw text (w,x,y,z) = self.get_rect(dc) dc.SetFont(self.font) - dc.DrawText(self.text_string, self.posx, self.posy) + text_string = self.text_string.replace('"', '"').replace(''', "'") + dc.DrawText(text_string, self.posx, self.posy) dc.SetTextForeground(wx.Colour(0,0,0)) def toxml(self, action="update"): @@ -119,21 +120,21 @@ else: return '' def takedom(self, xml_dom): - self.text_string = xml_dom.getAttribute("text_string") - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("posy"): self.posy = int(xml_dom.getAttribute("posy")) - if xml_dom.hasAttribute("posx"): self.posx = int(xml_dom.getAttribute("posx")) - if xml_dom.hasAttribute("weight"): - self.weight = int(xml_dom.getAttribute("weight")) + self.text_string = xml_dom.get("text_string") + self.id = xml_dom.get("id") + if xml_dom.get("posy") != None: self.posy = int(xml_dom.get("posy")) + if xml_dom.get("posx") != None: self.posx = int(xml_dom.get("posx")) + if xml_dom.get("weight"): + self.weight = int(xml_dom.get("weight")) self.font.SetWeight(self.weight) - if xml_dom.hasAttribute("style"): - self.style = int(xml_dom.getAttribute("style")) + if xml_dom.get("style") != None: + self.style = int(xml_dom.get("style")) self.font.SetStyle(self.style) - if xml_dom.hasAttribute("pointsize"): - self.pointsize = int(xml_dom.getAttribute("pointsize")) + if xml_dom.get("pointsize") != None: + self.pointsize = int(xml_dom.get("pointsize")) self.font.SetPointSize(self.pointsize) - if xml_dom.hasAttribute("color") and xml_dom.getAttribute("color") != '': - self.textcolor = xml_dom.getAttribute("color") + if xml_dom.get("color") != None and xml_dom.get("color") != '': + self.textcolor = xml_dom.get("color") if self.textcolor == '#0000000': self.textcolor = '#000000' class WhiteboardLine: @@ -231,16 +232,16 @@ return '' def takedom(self, xml_dom): - self.line_string = xml_dom.getAttribute("line_string") - self.id = xml_dom.getAttribute("id") - if xml_dom.hasAttribute("upperleftx"): self.upperleft.x = int(xml_dom.getAttribute("upperleftx")) - if xml_dom.hasAttribute("upperlefty"): self.upperleft.y = int(xml_dom.getAttribute("upperlefty")) - if xml_dom.hasAttribute("lowerrightx"): self.lowerright.x = int(xml_dom.getAttribute("lowerrightx")) - if xml_dom.hasAttribute("lowerrighty"): self.lowerright.y = int(xml_dom.getAttribute("lowerrighty")) - if xml_dom.hasAttribute("color") and xml_dom.getAttribute("color") != '': - self.linecolor = xml_dom.getAttribute("color") + self.line_string = xml_dom.get("line_string") + self.id = xml_dom.get("id") + if xml_dom.get("upperleftx") != None: self.upperleft.x = int(xml_dom.get("upperleftx")) + if xml_dom.get("upperlefty") != None: self.upperleft.y = int(xml_dom.get("upperlefty")) + if xml_dom.get("lowerrightx") != None: self.lowerright.x = int(xml_dom.get("lowerrightx")) + if xml_dom.get("lowerrighty") != None: self.lowerright.y = int(xml_dom.get("lowerrighty")) + if xml_dom.get("color") != None and xml_dom.get("color") != '': + self.linecolor = xml_dom.get("color") if self.linecolor == '#0000000': self.linecolor = '#000000' - if xml_dom.hasAttribute("width"): self.linewidth = int(xml_dom.getAttribute("width")) + if xml_dom.get("width") != None: self.linewidth = int(xml_dom.get("width")) ##----------------------------- ## whiteboard layer @@ -369,7 +370,7 @@ def add_text(self, text_string, pos, style, pointsize, weight, color="#000000"): id = 'text-' + self.canvas.session.get_next_id() - text = WhiteboardText(id,text_string, pos, style, pointsize, weight, color) + text = WhiteboardText(id, text_string, pos, style, pointsize, weight, color) self.texts.append(text) xml_str = "" xml_str += text.toxml("new") @@ -416,13 +417,13 @@ else: return "" def layerTakeDOM(self, xml_dom): - serial_number = xml_dom.getAttribute('serial') - if serial_number != "": self.serial_number = int(serial_number) - children = xml_dom._get_childNodes() + serial_number = xml_dom.get('serial') + if serial_number != None: self.serial_number = int(serial_number) + children = xml_dom.getchildren() for l in children: - nodename = l._get_nodeName() - action = l.getAttribute("action") - id = l.getAttribute('id') + nodename = l.tag + action = l.get("action") + id = l.get('id') try: if self.serial_number < int(id.split('-')[2]): self.serial_number = int(id.split('-')[2]) except: pass @@ -436,17 +437,17 @@ elif action == "new": if nodename == "line": try: - line_string = l.getAttribute('line_string') - upperleftx = l.getAttribute('upperleftx') - upperlefty = l.getAttribute('upperlefty') - lowerrightx = l.getAttribute('lowerrightx') - lowerrighty = l.getAttribute('lowerrighty') + line_string = l.get('line_string') + upperleftx = l.get('upperleftx') + upperlefty = l.get('upperlefty') + lowerrightx = l.get('lowerrightx') + lowerrighty = l.get('lowerrighty') upperleft = wx.Point(int(upperleftx),int(upperlefty)) lowerright = wx.Point(int(lowerrightx),int(lowerrighty)) - color = l.getAttribute('color') + color = l.get('color') if color == '#0000000': color = '#000000' - id = l.getAttribute('id') - width = int(l.getAttribute('width')) + id = l.get('id') + width = int(l.get('width')) except: line_string = upperleftx = upperlefty = lowerrightx = lowerrighty = color = 0 continue @@ -454,15 +455,15 @@ self.lines.append(line) elif nodename == "text": try: - text_string = l.getAttribute('text_string') - style = l.getAttribute('style') - pointsize = l.getAttribute('pointsize') - weight = l.getAttribute('weight') - color = l.getAttribute('color') + text_string = l.get('text_string') + style = l.get('style') + pointsize = l.get('pointsize') + weight = l.get('weight') + color = l.get('color') if color == '#0000000': color = '#000000' - id = l.getAttribute('id') - posx = l.getAttribute('posx') - posy = l.getAttribute('posy') + id = l.get('id') + posx = l.get('posx') + posy = l.get('posy') pos = wx.Point(0,0) pos.x = int(posx) pos.y = int(posy) diff -r b29454610f36 -r 9230a33defd9 orpg/mapper/whiteboard_msg.py --- a/orpg/mapper/whiteboard_msg.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/mapper/whiteboard_msg.py Wed Jun 16 03:06:20 2010 -0500 @@ -80,11 +80,11 @@ def init_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.init_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - item = item_msg(self.p_lock,c._get_nodeName()) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.init_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + item = item_msg(self.p_lock,c.tag) try: item.init_from_dom(c) except Exception, e: print e @@ -105,11 +105,11 @@ def set_from_dom(self,xml_dom): self.p_lock.acquire() - if xml_dom.tagName == self.tagname: - if xml_dom.getAttributeKeys(): - for k in xml_dom.getAttributeKeys(): self.set_prop(k,xml_dom.getAttribute(k)) - for c in xml_dom._get_childNodes(): - item = item_msg(self.p_lock, c._get_nodeName()) + if xml_dom.tag == self.tagname: + if xml_dom.keys(): + for k in xml_dom.keys(): self.set_prop(k,xml_dom.get(k)) + for c in xml_dom.getchildren(): + item = item_msg(self.p_lock, c.tag) try: item.set_from_dom(c) except Exception, e: print e diff -r b29454610f36 -r 9230a33defd9 orpg/networking/gsclient.py --- a/orpg/networking/gsclient.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/networking/gsclient.py Wed Jun 16 03:06:20 2010 -0500 @@ -349,7 +349,9 @@ i = self.room_list.GetItemCount() if (data[2]=="1") or (data[2]=="True"): pwd="yes" else: pwd="no" - self.room_list.InsertStringItem(i,data[1]) + name = data[1].replace('&', "&") + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">").replace('"', '"').replace(''', "'") + self.room_list.InsertStringItem(i, name) self.room_list.SetStringItem(i,1,data[3]) self.room_list.SetStringItem(i,2,pwd) self.room_list.SetItemData(i,int(data[0])) @@ -441,7 +443,9 @@ i = self.room_list.GetItemCount() if (g[2]=="True") or (g[2]=="1") : pwd="yes" else: pwd="no" - self.room_list.InsertStringItem(i, g[1]) + name = g[1].replace('&', "&") + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") + self.room_list.InsertStringItem(i, name) self.room_list.SetStringItem(i, 1, g[3]) self.room_list.SetStringItem(i, 2, pwd) self.room_list.SetItemData(i, int(g[0])) @@ -481,7 +485,9 @@ rooms = n.findall('room') for room in rooms: - self.rmList[address].append((room.get("id"), room.get("name"), + name = room.get('name').replace('&', "&") + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") + self.rmList[address].append((room.get("id"), name, room.get("pwd"), room.get("num_users"))) self.svrList.sort(server_instance_compare) @@ -568,36 +574,7 @@ name = self.texts["room_name"].GetValue() boot_pwd = self.texts["room_boot_pwd"].GetValue() minversion = self.texts["room_min_version"].GetValue() - # - # Check for & in name. We want to allow this becaus of its common use in D&D. - # - loc = name.find("&") - oldloc=0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "&" + e - oldloc = loc+1 - loc = name.find('"') - oldloc=0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + ""e;" + e - oldloc = loc+1 - loc = name.find("'") - oldloc=0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 + if self.buttons['gs_pwd'].GetValue(): pwd = self.texts["room_pwd"].GetValue() else: pwd = "" if name == "": wx.MessageBox("Invalid Name","Error"); diff -r b29454610f36 -r 9230a33defd9 orpg/networking/meta_server_lib.py --- a/orpg/networking/meta_server_lib.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/networking/meta_server_lib.py Wed Jun 16 03:06:20 2010 -0500 @@ -29,7 +29,7 @@ #added debug flag for meta messages to cut console server spam --Snowdog -META_DEBUG = 0 +META_DEBUG = False __version__ = "$Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $" @@ -42,17 +42,15 @@ from threading import * from random import uniform +import urllib2 from urllib import urlopen, urlencode from orpg.tools.orpg_log import debug -from xml.etree.ElementTree import Element, fromstring +from xml.etree.ElementTree import Element, fromstring, parse, tostring metacache_lock = RLock() -def get_server_dom(data=None,path=None, string=False): - # post data at server and get the resulting DOM - if path == None: - # get meta server URI - path = getMetaServerBaseURL() +def get_server_dom(data=None, path=None, string=False): + if path[len(path)-1] != "/": path += '/' # POST the data if META_DEBUG: @@ -61,9 +59,9 @@ print "==========================================" print data print - file = urlopen(path, data) - data = file.read() - file.close() + #recvdata = urllib2.Request(path, data) + response = urllib2.urlopen(path, data) + data = response.read() # Remove any leading or trailing data. This can happen on some satellite connections p = re.compile('(.*?)',re.DOTALL|re.IGNORECASE) @@ -77,9 +75,8 @@ print data print # build dom - etreeEl = data - if not string: return fromstring(etreeEl) - else: return etreeEl + if string: return data + else: return fromstring(data) def post_server_data(name, realHostName=None): if realHostName: data = urlencode({"server_data[name]":name, @@ -90,7 +87,7 @@ else: data = urlencode({"server_data[name]":name, "server_data[version]":PROTOCOL_VERSION, "act":"new"}) - path = component.get('settings').get('MetaServerBaseURL') #getMetaServerBaseURL() + path = component.get('settings').get('MetaServerBaseURL') #getMetaServerList() etreeEl = get_server_dom(data, path) return int(etreeEl.get('id')) @@ -111,49 +108,38 @@ def byStartAttribute(first, second): # This function is used to easily sort a list of nodes by their start time # Ensure there is something to sort with for each - first_start = int(first.get('start')) or 0 second_start = int(second.get('start')) or 0 - # Return the result of the cmp function on the two strings return cmp(first_start, second_start) def byNameAttribute(first, second): # This function is used to easily sort a list of nodes by their name attribute # Ensure there is something to sort with for each - first_name = first.get('name') or '' second_name = second.get('name') or '' - # Return the result of the cmp function on the two strings return cmp(first_name,second_name) -def get_server_list(versions = None, sort_by="start"): +def get_server_list(versions=None, sort_by="start"): data = urlencode({"version":PROTOCOL_VERSION,"ports":"%"}) - all_metas = getMetaServers(versions, 1) # get the list of metas - base_meta = getMetaServerBaseURL() - + #all_metas = getMetaServers(versions, False) # get the list of metas + meta_list = getMetaServerList() #all_metas.reverse() # The last one checked will take precedence, so reverse the order # so that the top one on the actual list is checked last return_hash = {} # this will end up with an amalgamated list of servers - for meta in all_metas: # check all of the metas + for meta in meta_list: # check all of the metas #get the server's xml from the current meta bad_meta = 0 #print "Getting server list from " + meta + "..." - try: xml_dom = get_server_dom(data=data, path=meta) - except: bad_meta = 1 #print "Trouble getting servers from " + meta + "..." + try: xml_dom = get_server_dom(data, meta.get('url')) + except: bad_meta = 1; print "Trouble getting servers from " + meta.get('url') + "..." if bad_meta: continue - if base_meta == meta: updateMetaCache(xml_dom) #print "This is our base meta: " + meta node_list = xml_dom.findall('server') - if len(node_list): # if there are entries in the node list - # otherwise, just loop to next meta - - # for each node found, we're going to check the nodes from prior - # metas in the list. If a match is found, then use the new values. + if len(node_list): for n in node_list: - # set them from current node if not n.get('name'): n.set('name','NO_NAME_GIVEN') name = n.get('name') if not n.get('num_users'): n.set('num_users','N/A') @@ -165,24 +151,15 @@ n.set('meta',meta) end_point = str(address) + ":" + str(port) if return_hash.has_key(end_point): + print end_point + print n + if META_DEBUG: print "Replacing duplicate server entry at " + end_point return_hash[end_point] = n - - # At this point, we have an amalgamated list of servers - # Now, we have to construct a new DOM to pass back. - - # Create a servers element server_list = Element('servers') - - # get the nodes stored in return_hash sort_list = return_hash.values() - - # sort them by their name attribute. Uses byNameAttribute() - # defined above as a comparison function if sort_by == "start": sort_list.sort(byStartAttribute) elif sort_by == "name": sort_list.sort(byNameAttribute) - - # Add each node to the DOM for n in sort_list: server_list.append(n) return server_list @@ -216,122 +193,32 @@ if META_DEBUG: traceback.print_exc() print "Meta Server Lib: UpdateMetaCache(): " + str(e) -def getRawMetaList(path=None): - ### Alpha ### - """This code will allow for a list of metas to be created. Future developement will more integrate the list of metas""" - if path != None: - metas = [] - data = urlencode({"version":PROTOCOL_VERSION,"ports":"%"}) - xml_dom = get_server_dom(data, path) - node_list = fromstring(xml_dom).findall('meta_server') - if len(node_list): - for n in node_list: - metas.append(n.get('path')) - return metas + +def getMetaServerList(): + # get meta server URL + meta_list = fromstring(""" + + + + """ + ) try: - try: - metacache_lock.acquire() - # Read in the metas - validate.config_file("metaservers.cache","metaservers.cache") - ini = open(dir_struct["user"]+"metaservers.cache","r") - metas = ini.readlines() - ini.close() - return metas - finally: - metacache_lock.release() - except Exception, e: - if META_DEBUG: traceback.print_exc() - print "Meta Server Lib: getRawMetaList(): " + str(e) - return [] - -def getMetaServers(versions = None, pick_random=0): - """ - get meta server URLs as a list - versions is a list of acceptable version numbers. - A False truth value will use getMetaServerBaseURL() - set a default if we have weird reading problems - default_url = "http://www.openrpg.com/openrpg_servers.php" - """ - - ### Pre Alpha Design ### - """ Here is how to handle Multiple Meta servers, and probably the best way to do it. Create an XML file that contains nodes with the various servers. Users will grab that meta data and have the option to connect to multiple meta servers which will allow them to find all the rooms. A check box should be used so if one server faile the users can continue without much lag. When creating a server hosts will need to select a meta to go too. This should be in the final of Ornery Orc.""" - meta_names = [] - if(versions): # If versions are supplied, then look in metaservers.conf - try: - """ - read in the metas from file - format of file is one meta entry per line - each entry will be the meta url, followed by one or more version numbers that it - handle. Generally, this will be either a 1 for the original Meta format, or - 2 for the new one. - """ - # Read in the metas - #Adding a path object will attempt to look for a meta_network. - metas = getRawMetaList() - - # go through each one to check if it should be returned, based on the - # version numbers allowed. - for meta in metas: - # split the line on whitespace - # obviously, your meta servers urls shouldn't contain whitespace. duh. - words = meta.split() - success = 0 # init success flag for version check - for version in versions: # run through each allowed version from caller - if version in words[1:]: # if the allowed version token was found - success += 1 # then increment the success indicator - if success: # if the meta entry is acceptable to the caller - meta_names.append(words[0]) # add the entry - if META_DEBUG: print "adding metaserver " + meta - - # at this point, we should have at least one name from the cache. If not ... - if not meta_names: - default_meta = getMetaServerBaseURL() # grab the meta from ini.xml - meta_names.append(default_meta) # add it to the return list - # print "Warning!!\nNo valid metaservers cached." - # print "Using meta from MetaServerBaseURL: " + default_meta + "\n" - # if we have more than one and want a random one - elif pick_random: - if META_DEBUG: print "choosing random meta from: " + str(meta_names) - i = int(uniform(0,len(meta_names))) - #meta = meta_names[i] - meta_names = [meta_names[i]] - if META_DEBUG: print "using: " + str(meta_names) - else: - if META_DEBUG: print "using all metas: " + str(meta_names) - return meta_names - except Exception,e: - print e - #print "using default meta server URI: " + default_url - metas = [] - #metas.append(default_url) - return metas # return an empty list - else: # otherwise, use MetaServerBaseURL() - url = getMetaServerBaseURL() - meta_names.append(url) - return meta_names - -def getMetaServerBaseURL(): - # get meta server URL - url = "http://orpgmeta.appspot.com/" - try: + component.get('validate').config_file("metaservers.xml","default_metaservers.xml") component.get('validate').config_file("settings.xml","default_settings.xml") - ini = open(dir_struct["user"]+"settings.xml","r") - txt = ini.read() - xml = component.get('xml') - tree = xml.parseXml(txt)._get_documentElement() - ini.close() - node_list = tree.getElementsByTagName("MetaServerBaseURL") - if node_list: - url = node_list[0].getAttribute("value") - print url - # allow tree to be collected - try: tree.unlink() - except: pass - - except Exception,e: - print e - #print "using meta server URI: " + url - return url + setting = parse(dir_struct["user"]+"settings.xml") + tree = setting.getroot() + node_list = tree.getiterator("MetaServers") + if len(node_list) == 0: + component.get('frame').add_setting('Meta Servers') + setting = parse(dir_struct["user"]+"settings.xml") + metas = parse(dir_struct["user"]+'metaservers.xml').getroot() + else: + meta = node_list[0].get("value") + metas = parse(dir_struct["user"]+meta).getroot() + meta_list = metas.findall('meta') + return meta_list + except Exception,e: print e + return meta_list """ Beginning of Class registerThread @@ -386,6 +273,7 @@ self.destroy = 0 # Used to flag that this thread should die self.port = str(port) self.register_callback = register_callback # set a method to call to report result of register + self.IdAttempts = 0 """ This thread will communicate with one and only one Meta. If the Meta in ini.xml is changed after @@ -396,7 +284,7 @@ it easier to have multiple registerThreads going to keep the server registered on multiple (compatible) Metas. """ - if MetaPath == None: self.path = getMetaServerBaseURL() # Do this if no Meta specified + if MetaPath == None: self.path = getMetaServerList() # Do this if no Meta specified else: self.path = MetaPath def getIdAndCookie(self): @@ -469,16 +357,18 @@ if not self.isAlive(): # check to see if this thread is dead return 1 # If so, return an error result # Do the actual unregistering here - data = urlencode( {"server_data[id]":self.id, + data = urlencode( { "server_data[id]":self.id, "server_data[cookie]":self.cookie, "server_data[version]":PROTOCOL_VERSION, "act":"unregister"} ) - try: # this POSTS the request and returns the result - xml_dom = get_server_dom(data=data, path=self.path) - if xml_dom.get("errmsg"): - print "Error durring unregistration: " + xml_dom.get("errmsg") - except: - if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us." + for path in getMetaServerList(): + try: # this POSTS the request and returns the result + etreeEl = get_server_dom(data, path.get('url')) + if etreeEl.get("errmsg") != None: + print "Error durring unregistration: " + etreeEl.get("errmsg") + except Exception, e: + if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us." + if META_DEBUG: print e # If there's an error, echo it to the console # No special handling is required. If the de-registration worked we're done. If @@ -509,11 +399,14 @@ # Set the server's attibutes, if specified. if name: self.name = name - if num_users != None: self.num_users = num_users + if num_users != None: + try: self.num_users = len(num_users) + except: self.num_users = num_users + else: self.num_users = 0 if realHostName: self.realHostName = realHostName # build POST data if self.realHostName: - data = urlencode( {"server_data[id]":self.id, + data = urlencode( { "server_data[id]":self.id, "server_data[cookie]":self.cookie, "server_data[name]":self.name, "server_data[port]":self.port, @@ -523,7 +416,7 @@ "server_data[address]": self.realHostName } ) else: if META_DEBUG: print "Letting meta server decide the hostname to list..." - data = urlencode( {"server_data[id]":self.id, + data = urlencode( { "server_data[id]":self.id, "server_data[cookie]":self.cookie, "server_data[name]":self.name, "server_data[port]":self.port, @@ -531,11 +424,11 @@ "server_data[num_users]":self.num_users, "act":"register"} ) try: # this POSTS the request and returns the result - etreeEl = get_server_dom(data=data, path=self.path) - except: + etreeEl = get_server_dom(data, self.path) + except Exception, e: if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." if META_DEBUG: print data - if META_DEBUG: print + if META_DEBUG: print e self.interval = 0 """ If we are in the registerThread thread, then setting interval to 0 @@ -552,10 +445,10 @@ return 0 # indicates that it was okay to call, not that no errors occurred # If there is a DOM returned .... - if etreeEl: + if etreeEl != None: # If there's an error, echo it to the console - if etreeEl.get("errmsg"): - print "Error durring registration: " + etreeEl.get("errmsg") + if etreeEl.get("errmsg") != None: + print "Error durring registration at: " +path.get('url')+ " Error: " +etreeEl.get("errmsg") if META_DEBUG: print data if META_DEBUG: print """ @@ -580,11 +473,12 @@ self.interval = int(etreeEl.get("interval")) self.id = etreeEl.get("id") self.cookie = etreeEl.get("cookie") - if not etreeEl.get("errmsg"): updateMetaCache(xml_dom) - except: + #if etreeEl.get("errmsg") == None: updateMetaCache(xml_dom) + except Exception, e: if META_DEBUG: print if META_DEBUG: print "OOPS! Is the Meta okay? It should be returning an id, cookie, and interval." if META_DEBUG: print "Check to see what it really returned.\n" + if META_DEBUG: print e # Let xml_dom get garbage collected try: xml_dom.unlink() except: pass diff -r b29454610f36 -r 9230a33defd9 orpg/networking/mplay_client.py --- a/orpg/networking/mplay_client.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/networking/mplay_client.py Wed Jun 16 03:06:20 2010 -0500 @@ -38,7 +38,7 @@ from orpg.orpg_version import CLIENT_STRING, PROTOCOL_VERSION, VERSION from orpg.orpgCore import component -from orpg.orpg_xml import xml +#from orpg.orpg_xml import xml from orpg.tools.orpg_log import debug from orpg.tools.settings import settings @@ -81,9 +81,9 @@ STATUS_SET_URL = 1 def parseXml(data): + debug(('Developers note. Deprecated call to parseXml!!'), parents=True) "parse and return doc" - doc = xml.parseXml(data) - doc.normalize() + doc = fromstring(data) return doc def myescape(data): @@ -387,7 +387,6 @@ def __init__(self,name,callbacks): client_base.__init__(self) component.add('mp_client', self) - self.xml = component.get('xml') self.set_name(name) self.on_receive = callbacks['on_receive'] self.on_mplay_event = callbacks['on_mplay_event'] diff -r b29454610f36 -r 9230a33defd9 orpg/networking/mplay_server.py --- a/orpg/networking/mplay_server.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/networking/mplay_server.py Wed Jun 16 03:06:20 2010 -0500 @@ -51,6 +51,7 @@ from mplay_client import MPLAY_LENSIZE from orpg.dirpath import dir_struct import orpg.tools.validate +import htmlentitydefs from orpg.mapper.map_msg import * from threading import Lock, RLock @@ -316,7 +317,7 @@ self.banDoc = self.banDom.getroot() for element in self.banDom.findall('banned'): - playerName = element.get('name').replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">") + playerName = element.get('name').replace("&", "&").replace("<", "<").replace('"', "").replace(">", ">") playerIP = element.get('ip') self.ban_list[playerIP] = {} self.ban_list[playerIP]['ip'] = playerIP @@ -336,7 +337,7 @@ etreeEl = Element('server') for ip in self.ban_list: el = Element('banned') - el.set('name', str(self.ban_list[ip]['name'].replace("&", "&").replace("<", "<").replace(""", '"').replace(">", ">"))) + el.set('name', str(self.ban_list[ip]['name'].replace("&", "&").replace("<", "<").replace("", '"').replace(">", ">"))) el.set('ip', str(self.ban_list[ip]['ip'])) etreeEl.append(el) file = open(self.userPath + self.banFile ,"w") @@ -616,7 +617,7 @@ def register_callback(instance, xml_dom = None, source=None): if xml_dom: # if we get something - if source == getMetaServerBaseURL(): # if the source of this DOM is the authoritative meta + if source == getMetaServerList(): # if the source of this DOM is the authoritative meta try: metacache_lock.acquire() curlist = getRawMetaList() # read the raw meta cache lines into a list @@ -648,21 +649,40 @@ def registerRooms(self, args=None): rooms = '' - id = '0' - time.sleep(500) - for rnum in self.groups.keys(): - rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][name]":self.groups[rnum].name, - "room_data[rooms][" + str(rnum) + "][pwd]":str(self.groups[rnum].pwd != "")})+'&' - for pid in self.groups[rnum].players: - rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][players]["+str(pid)+"]":self.players[pid].name,})+'&' + serverId = '0' + x = 0 + cache = {} for meta in self.metas.keys(): - while id == '0': - id, cookie = self.metas[meta].getIdAndCookie() - data = urllib.urlencode( {"room_data[server_id]":id, - "act":'registerrooms'}) - get_server_dom(data+'&'+rooms, self.metas[meta].path, string=True) + # There is no point in wasting our planetary resources on attempting to register rooms to a meta + # that does not provide that service. When they eventually get their head out of the elitist clouds + # this work around can be removed. + if meta.get('url') != 'http://orpgmeta.appspot.com': + cache[meta] = self.metas[meta] + for meta in cache.keys(): + self.log_msg("Registering rooms too: " +meta.get('url')) + self.log_msg("Obtaining Server ID from: " +meta.get('url')) + for x in range (1, 100): + serverId, cookie = self.metas[meta].getIdAndCookie() + if serverId == '0': + self.metas[meta].IdAttempts += 100 + if self.metas[meta].IdAttempts > 1000: + self.metas[meta].unregister() + self.log_msg("Deleting Meta: " +meta.get('url')+ " after 1000 attempts.") + del self.metas[meta] + break + if serverId != '0': + self.log_msg("Obtained Server ID: " +serverId+ " from: " +meta.get('url')) + self.metas[meta].IdAttempts = 0 + for rnum in self.groups.keys(): + rooms += urllib.urlencode({"room_data[rooms][" +str(rnum)+ "][name]":self.groups[rnum].name, + "room_data[rooms][" +str(rnum)+ "][pwd]":str(self.groups[rnum].pwd != ""), + "room_data[rooms][" +str(rnum)+ "][players]":str(len(self.groups[rnum].players)) + })+'&' + data = urllib.urlencode({"room_data[server_id]":serverId, + "act":'registerrooms'}) + get_server_dom(data+'&'+rooms, meta.get('url'), string=True) - def register(self,name_given=None): + def register(self, name_given=None): if name_given == None: name = self.name else: self.name = name = name_given name = self.clean_published_servername(name) @@ -672,11 +692,10 @@ else: num_players = 0 # request only Meta servers compatible with version 2 - metalist = getMetaServers(versions=["2"]) + metalist = getMetaServerList() if self.show_meta_messages != 0: self.log_msg("Found these valid metas:") - for meta in metalist: self.log_msg("Meta:" + meta) - + for meta in metalist: self.log_msg("Meta:" + meta.get('url')) """ # Go through the list and see if there is already a running register # thread for the meta. @@ -686,26 +705,27 @@ # iterate through the currently running metas and prune any # not currently listed in the Meta Server list. """ - if self.show_meta_messages != 0: self.log_msg( "Checking running register threads for outdated metas.") for meta in self.metas.keys(): if self.show_meta_messages != 0: self.log_msg("meta:" + meta + ": ") if not meta in metalist: # if the meta entry running is not in the list if self.show_meta_messages != 0: self.log_msg( "Outdated. Unregistering and removing") self.metas[meta].unregister() + self.log_msg("Unregistering from: " +meta.get('url')) del self.metas[meta] else: if self.show_meta_messages != 0: self.log_msg( "Found in current meta list. Leaving intact.") # Now call register() for alive metas or start one if we need one for meta in metalist: - if self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive(): + self.log_msg("Registering too: " +meta.get('url')) + if (self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive()): self.metas[meta].register(name=name, realHostName=self.server_address, num_users=num_players) else: self.metas[meta] = registerThread(name=name, realHostName=self.server_address, - num_users=num_players, MetaPath=meta, port=self.server_port, + num_users=num_players, MetaPath=meta.get('url'), port=self.server_port, register_callback=self.register_callback) self.metas[meta].start() @@ -723,8 +743,9 @@ # Instead, loop through all existing meta threads and unregister them """ - for meta in self.metas.values(): - if meta and meta.isAlive(): meta.unregister() + for meta in self.metas.keys(): + self.log_msg("Unregistering from: " +meta.get('url')) + if self.metas[meta] and self.metas[meta].isAlive(): self.metas[meta].unregister() self.be_registered = 0 """ @@ -1211,11 +1232,9 @@ self.log_msg(("update_group", (self.groups[LOBBY_ID].name, LOBBY_ID, len(self.groups[LOBBY_ID].players) ) )) cmsg = ("connect", props) ################################################# self.log_msg(cmsg) - - # If already registered then re-register, thereby updating the Meta - # on the number of players - if self.be_registered: - self.register() + for meta in self.metas.keys(): + self.metas[meta].num_users = len(self.players) + thread.start_new_thread(self.registerRooms,(0,)) except: traceback.print_exc() @@ -1673,33 +1692,8 @@ # Check for & in name. We want to allow this because of its common # use in d&d games. try: - loc = name.find("&") - oldloc = 0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - value = b + "&" + e - oldloc = loc+1 - loc = name.find("'") - oldloc = 0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 - loc = name.find('"') - oldloc = 0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + """ + e - oldloc = loc+1 + name = name.replace('&', '&') + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") oldroomname = self.groups[gid].name self.groups[gid].name = str(name) lmessage = "Room name changed to from \"" + oldroomname + "\" to \"" + name + "\"" @@ -1726,34 +1720,8 @@ # Check for & in name. We want to allow this because of its common # use in d&d games. - - loc = name.find("&") - oldloc = 0 - while loc > -1: - loc = name.find("&",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "&" + e - oldloc = loc+1 - loc = name.find("'") - oldloc = 0 - while loc > -1: - loc = name.find("'",oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + "'" + e - oldloc = loc+1 - loc = name.find('"') - oldloc = 0 - while loc > -1: - loc = name.find('"',oldloc) - if loc > -1: - b = name[:loc] - e = name[loc+1:] - name = b + """ + e - oldloc = loc+1 + name = name.replace('&', '&') + name = name.replace('"', '"e;').replace("'", ''').replace("<", "<").replace(">", ">") group_id = str(self.next_group_id) self.next_group_id += 1 @@ -1809,14 +1777,10 @@ del self.players[id] self.log_msg(dmsg) self.log_msg(("disconnect",id)) - """ - # If already registered then re-register, thereby updating the Meta - # on the number of players - # Note: Upon server shutdown, the server is first unregistered, so - # this code won't be repeated for each player being deleted. - """ - if self.be_registered: - self.register() + self.log_msg(("update_group", (self.groups[group_id].name, group_id, len(self.groups[group_id].players) ))) + for meta in self.metas.keys(): + self.metas[meta].num_users = len(self.players) + thread.start_new_thread(self.registerRooms,(0,)) except Exception, e: self.log_msg( ('exception', str(e)) ) self.log_msg("Explicit garbage collection shows %s undeletable items." % str(gc.collect())) @@ -1825,30 +1789,32 @@ act = xml_dom.get("action") group_id = self.players[id].group_id ip = self.players[id].ip - self.log_msg("Player with IP: " + str(ip) + " joined.") ServerPlugins.setPlayer(self.players[id]) self.send_to_group(id,group_id,data) if act=="new": try: self.send_player_list(id,group_id) self.send_group_list(id) + self.log_msg("Player with IP: " + str(ip) + " connected.") except Exception, e: self.log_msg( ('exception', str(e)) ); traceback.print_exc() elif act=="del": self.del_player(id,group_id) self.check_group(id, group_id) + self.log_msg("Player with IP: " + str(ip) + " disconnected.") elif act=="update": self.players[id].take_dom(xml_dom) + self.log_msg("Player with IP: " + str(ip) + " updated.") self.log_msg(("update", {"id": id, - "name": xml_dom.get("name"), - "status": xml_dom.get("status"), - "role": xml_dom.get("role"), - "ip": str(ip), - "group": xml_dom.get("group_id"), - "room": xml_dom.get("name"), - "boot": xml_dom.get("rm_boot"), - "version": xml_dom.get("version"), - "ping": xml_dom.get("time") \ - })) + "name": xml_dom.get("name"), + "status": xml_dom.get("status"), + "role": xml_dom.get("role"), + "ip": str(ip), + "group": xml_dom.get("group_id"), + "room": xml_dom.get("name"), + "boot": xml_dom.get("rm_boot"), + "version": xml_dom.get("version"), + "ping": xml_dom.get("time") \ + })) def strip_cheat_roll(self, string): try: @@ -1988,7 +1954,7 @@ given_boot_pwd = None try: xml_dom = XML(msg) - given_boot_pwd = xml_dom.get("boot_pwd") + given_boot_pwd = xml_dom.find('boot').get("boot_pwd") except Exception, e: print "Error in parse of boot message, Ignoring." @@ -2011,31 +1977,31 @@ """ if given_boot_pwd == server_admin_pwd: # Send a message to everyone in the room, letting them know someone has been booted - boot_msg = "Booting '(%s) %s' from server..." % (from_id, group_id, to_id, self.players[to_id].name) + msg = '' + msg += 'Booting (' +str(to_id)+ ') ' +self.players[to_id].name+ ' from server...' + + boot_msg = self.buildMsg('all', '0', group_id, msg) self.log_msg("boot_msg:" + boot_msg) self.send_to_group( "0", group_id, boot_msg ) time.sleep( 1 ) self.log_msg("Booting player " + str(to_id) + " from server.") - # Send delete player event to all self.send_to_group("0",group_id,self.players[to_id].toxml("del")) - # Remove the player from local data structures self.del_player(to_id,group_id) - # Refresh the group data self.check_group(to_id, group_id) elif actual_boot_pwd == given_boot_pwd: # Send a message to everyone in the room, letting them know someone has been booted - boot_msg = "Booting '(%s) %s' from room..." % (from_id, group_id, to_id, self.players[to_id].name) + msg = '' + msg += 'Booting (' +str(to_id)+ ') ' +self.players[to_id].name+ ' from server...' + boot_msg = self.buildMsg('all', from_id, group_id, msg) self.log_msg("boot_msg:" + boot_msg) self.send_to_group( "0", group_id, boot_msg ) time.sleep( 1 ) - #dump player into the lobby self.move_player(to_id,"0") - # Refresh the group data self.check_group(to_id, group_id) else: @@ -2051,7 +2017,9 @@ finally: try: - if xml_dom: xml_dom.unlink() + try: + if xml_dom: xml_dom.unlink() + except: pass except Exception, e: traceback.print_exc() self.log_msg('Exception in xml_dom.unlink() ' + str(e)) @@ -2094,7 +2062,7 @@ configDom = parse(dir_struct["user"] + 'ban_list.xml') self.ban_list = {} for element in configDom.findall('banned'): - player = element.get('name').replace("&", "&").replace("<", "<").replace('"', """).replace(">", ">") + player = element.get('name').replace("&", "&").replace("<", "<").replace('"', "").replace(">", ">") ip = element.get('ip') self.ban_list[ip] = {} self.ban_list[ip]['ip'] = ip diff -r b29454610f36 -r 9230a33defd9 orpg/networking/mplay_server_gui.py --- a/orpg/networking/mplay_server_gui.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/networking/mplay_server_gui.py Wed Jun 16 03:06:20 2010 -0500 @@ -348,7 +348,10 @@ chat.set('type', '1') chat.set('version', '1.0') chat.text = broadcast - msg = self.main.server.server.buildMsg('all', '0', '1', tostring(chat)) + msg = self.main.server.server.buildMsg('all', + '0', + str(self.main.server.server.players[playerID]), + tostring(chat)) if len(msg): self.main.server.server.send_to_group('0', str(groupID), msg ) elif menuItem == 6: @@ -420,6 +423,7 @@ menu = wx.Menu() menu.Append(1, 'Start', 'Start server.') menu.Append(2, 'Stop', 'Shutdown server.') + menu.Append(16, 'Clear Log', 'Empty server log') menu.AppendSeparator() menu.Append(3, 'E&xit', 'Exit application.') self.Bind(wx.EVT_MENU, self.OnStart, id=1) @@ -455,6 +459,7 @@ self.Bind(wx.EVT_MENU, self.StopPingPlayers, id=8) self.Bind(wx.EVT_MENU, self.ConfigPingInterval, id=9) self.Bind(wx.EVT_MENU, self.LogToggle, id=10) + self.Bind(wx.EVT_MENU, self.ClearLog, id=16) self.mainMenu.Append( menu, '&Configuration') # Traipse Suite of Additions. @@ -562,6 +567,9 @@ def LogToggle(self, event): self.do_log = event.IsChecked() + def ClearLog(self, event): + self.log.SetValue('') + def OnLogMessage( self, event ): self.Log( event.message ) @@ -658,19 +666,20 @@ wx.EndBusyCursor() else: self.show_error("Server is already running.", "Error Starting Server") - def OnStop(self, event = None): + def OnStop(self, event=None): """ Stop server. """ if self.STATUS == SERVER_RUNNING: - self.OnUnregister() + self.OnUnregister(event) self.server.stop() self.STATUS = SERVER_STOPPED - self.sb.SetStatusText("Stopped", 3) - self.SetTitle(__appname__ + "- (stopped) - (unregistered)") - self.mainMenu.Enable(1, True) - self.mainMenu.Enable(2, False) - self.mainMenu.Enable(4, False) - self.mainMenu.Enable(5, False) - self.conns.DeleteAllItems() + if event != 'Quit': + self.sb.SetStatusText("Stopped", 3) + self.SetTitle(__appname__ + "- (stopped) - (unregistered)") + self.mainMenu.Enable(1, True) + self.mainMenu.Enable(2, False) + self.mainMenu.Enable(4, False) + self.mainMenu.Enable(5, False) + self.conns.DeleteAllItems() def OnRegister(self, event = None): """ Call into mplay_server's register() function. @@ -695,11 +704,12 @@ """ wx.BeginBusyCursor() self.server.server.unregister() - self.sb.SetStatusText("Unregistered", 4) - self.mainMenu.Enable(5, False) - self.mainMenu.Enable(4, True) - #self.mainMenu.Enable( 2, True ) - self.SetTitle(__appname__ + "- (running) - (unregistered)") + if event != 'Quit': + self.sb.SetStatusText("Unregistered", 4) + self.mainMenu.Enable(5, False) + self.mainMenu.Enable(4, True) + #self.mainMenu.Enable( 2, True ) + self.SetTitle(__appname__ + "- (running) - (unregistered)") wx.EndBusyCursor() def ModifyBanList(self, event): @@ -726,7 +736,7 @@ def ExitConfirmed(self, event=None): """ Quit the program. """ - self.OnStop() + self.OnStop('Quit') self.BanListDialog.Destroy() wx.CallAfter(self.Destroy) diff -r b29454610f36 -r 9230a33defd9 orpg/orpg_version.py --- a/orpg/orpg_version.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/orpg_version.py Wed Jun 16 03:06:20 2010 -0500 @@ -2,9 +2,9 @@ SERVER_MIN_CLIENT_VERSION = "1.7.1" #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed) -DISTRO = "Traipse Alpha" +DISTRO = "Traipse Beta" DIS_VER = "Ornery Orc" -BUILD = "100503-01" +BUILD = "100616-00" # This version is for network capability. PROTOCOL_VERSION = "1.2" diff -r b29454610f36 -r 9230a33defd9 orpg/orpg_windows.py --- a/orpg/orpg_windows.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/orpg_windows.py Wed Jun 16 03:06:20 2010 -0500 @@ -56,49 +56,54 @@ pos = string.rfind(file_name,'.') ext = string.lower(file_name[pos+1:]) img_type = 0 - recycle_bin = {"gif": wx.BITMAP_TYPE_GIF, "jpg": wx.BITMAP_TYPE_JPEG, + recycle_bin = {"gif": wx.BITMAP_TYPE_GIF, "jpg": wx.BITMAP_TYPE_JPEG, "jpeg": wx.BITMAP_TYPE_JPEG, "bmp": wx.BITMAP_TYPE_BMP, "png": wx.BITMAP_TYPE_PNG} - if recycle_bin.has_key(ext): img_type = recycle_bin[ext] - else: img_type = None - del recycle_bin; return img_type + if recycle_bin.has_key(ext): img_type = recycle_bin[ext] + else: img_type = None + del recycle_bin; return img_type ################################ ## Tabs ################################ class orpgTabberWnd(FNB.FlatNotebook): - def __init__(self, parent, closeable=False, size=wx.DefaultSize, style = False): + def __init__(self, parent, closeable=False, size=wx.DefaultSize, style=False): nbstyle = FNB.FNB_HIDE_ON_SINGLE_TAB|FNB.FNB_BACKGROUND_GRADIENT + if style: nbstyle |= style FNB.FlatNotebook.__init__(self, parent, -1, size=size, style=nbstyle) rgbcovert = orpg.tools.rgbhex.RGBHex() self.log = component.get("log") self.log.log("Enter orpgTabberWnd", ORPG_DEBUG) self.settings = component.get("settings") - tabtheme = self.settings.get_setting('TabTheme') - tabtext = self.settings.get_setting('TabTextColor') + tabtheme = self.settings.get('TabTheme') + tabtext = self.settings.get('TabTextColor') (tred, tgreen, tblue) = rgbcovert.rgb_tuple(tabtext) - tabbedwindows = component.get("tabbedWindows") - tabbedwindows.append(self) - component.add("tabbedWindows", tabbedwindows) + component.get("tabbedWindows").append(self) theme_dict = {'slanted&aqua': FNB.FNB_VC8, 'slanted&bw': FNB.FNB_VC8, 'flat&aqua': FNB.FNB_FANCY_TABS, - 'flat&bw': FNB.FNB_FANCY_TABS, 'customflat': FNB.FNB_FANCY_TABS, 'customslant': FNB.FNB_VC8, - 'slanted&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS, 'slant&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS} - nbstyle |= theme_dict[tabtheme] - if style: nbstyle |= style - self.SetWindowStyleFlag(nbstyle) + 'flat&bw': FNB.FNB_FANCY_TABS, 'customflat': FNB.FNB_FANCY_TABS, 'customslant': FNB.FNB_VC8} + #'slanted&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS, 'slant&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS} + if theme_dict.has_key(tabtheme): style |= theme_dict[tabtheme] + else: style |= theme_dict['customflat']; self.settings.change('TabTheme', 'customflat') + self.SetWindowStyleFlag(style) + + tabbg = self.settings.get('TabBackgroundGradient') + (red, green, blue) = rgbcovert.rgb_tuple(tabbg) + self.SetTabAreaColour(wx.Color(red, green, blue)) # Tas - sirebral. Planned changes to the huge statement below. if tabtheme == 'slanted&aqua': self.SetGradientColourTo(wx.Color(0, 128, 255)) self.SetGradientColourFrom(wx.WHITE) + self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'slanted&bw': self.SetGradientColourTo(wx.WHITE) self.SetGradientColourFrom(wx.WHITE) + self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'flat&aqua': - self.SetGradientColourFrom(wx.Color(0, 128, 255)) - self.SetGradientColourTo(wx.WHITE) + self.SetGradientColourTo(wx.Color(0, 128, 255)) + self.SetGradientColourFrom(wx.WHITE) self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'flat&bw': @@ -107,28 +112,21 @@ self.SetNonActiveTabTextColour(wx.BLACK) elif tabtheme == 'customflat': - gfrom = self.settings.get_setting('TabGradientFrom') - (red, green, blue) = rgbcovert.rgb_tuple(gfrom) - self.SetGradientColourFrom(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientTo')) + self.SetGradientColourTo(wx.Color(red, green, blue)) - gto = self.settings.get_setting('TabGradientTo') - (red, green, blue) = rgbcovert.rgb_tuple(gto) - self.SetGradientColourTo(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientFrom')) + self.SetGradientColourFrom(wx.Color(red, green, blue)) self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) elif tabtheme == 'customslant': - gfrom = self.settings.get_setting('TabGradientFrom') - (red, green, blue) = rgbcovert.rgb_tuple(gfrom) - self.SetGradientColourFrom(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientTo')) + self.SetGradientColourTo(wx.Color(red, green, blue)) - gto = self.settings.get_setting('TabGradientTo') - (red, green, blue) = rgbcovert.rgb_tuple(gto) - self.SetGradientColourTo(wx.Color(red, green, blue)) + (red, green, blue) = rgbcovert.rgb_tuple(self.settings.get_setting('TabGradientFrom')) + self.SetGradientColourFrom(wx.Color(red, green, blue)) self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) - tabbg = self.settings.get_setting('TabBackgroundGradient') - (red, green, blue) = rgbcovert.rgb_tuple(tabbg) - self.SetTabAreaColour(wx.Color(red, green, blue)) self.Refresh() self.log.log("Exit orpgTabberWnd", ORPG_DEBUG) diff -r b29454610f36 -r 9230a33defd9 orpg/orpg_xml.py --- a/orpg/orpg_xml.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/orpg_xml.py Wed Jun 16 03:06:20 2010 -0500 @@ -31,7 +31,7 @@ from orpg.tools.orpg_log import logger, debug class xml: - debug('Developers note. Deprecated call to orpg_xml!!') + debug(('Developers note. Deprecated call to orpg_xml!!'), parents=True) def __init__(self): pass diff -r b29454610f36 -r 9230a33defd9 orpg/templates/default_settings.xml --- a/orpg/templates/default_settings.xml Mon May 03 03:29:14 2010 -0500 +++ b/orpg/templates/default_settings.xml Wed Jun 16 03:06:20 2010 -0500 @@ -2,9 +2,9 @@ - + - + diff -r b29454610f36 -r 9230a33defd9 orpg/templates/feature.xml --- a/orpg/templates/feature.xml Mon May 03 03:29:14 2010 -0500 +++ b/orpg/templates/feature.xml Wed Jun 16 03:06:20 2010 -0500 @@ -65,40 +65,84 @@ - - Persistant users who wanted the stability of Traipse and the ease of Namespace have described to me how they envision Namespace should work. When I heard this I immediately realized that my method provided the aspects users wanted, but not simplicity in design this method would provide. The Traipse Namespace is a little different than Standard but it offers more stability in it's approach + Namespace 2.0 - There are two methods provided with the Traipse Namespace, and these two allow you to a great deal of control when you choose to use Namespace to reference your nodes. +Internal Namespace: !=NodeName=! or !=GridName::Row,Colum=! +External Namespace: !&Container::NodeName&! or !&Container::GridName::Row,Colum&! + +Namespace 2.0 now has two different ways of finding nodes in your gametree: Internal and +External. The new version will find nodes differently based on which method you use. With External you start looking from the gametree but can define a "container" to be more specific. With Internal you start looking from the "node" the reference is in and look through the tree backwards. You can now reference cells within a grid using either. -There is only one difference in how these two methods work, so once you get the hang of Namespace, you will always know how it works. The difference is, External starts looking from the Game Tree and gets more narrow where as Internal starts from the node it is inside and searchs backwards getting more broad. - - - Namespace Internal: -(Syntax) !=Node=! +*An explanation of terms* +Gametree: The list of objects on the left-hand side of the window that holds all your nodes. +Node: Refers to any object in the gametree. +Container: Refers only to those nodes that are capable of storing other nodes (Splitter, +Tabbers, Folder, Forms, etc.). Used here, it usually refers to the largest container, i.e. the +one that shows up in the gametree when fully collapsed. A Container can contain other +containers. +Internal Namespace: !=NodeName=! +-Used from within a node to call another node in the same container, such as a list node +calling a text node or grid. *Note* Will not work if multiple nodes within the same container +have the same name. Multiple nodes within the entirety of the gametree can have the same names +though as long as they are in different containers. +-Uses the !=NodeName=! syntax for normal nodes. +-Uses !=GridName::Row,Colum=! to reference cells within a grid + +Examples: +!=Strength=! +(Will find the node named “Strength” in the same container and insert it in place of +!=Strength=!) -Usage: When you use Namespace Internal the software finds the tree map of the node and searches for the top node. Once that node is found it will iterate through the node and look for the reference you have assigned. If it cannot find it in that node, then it will iterate through the map, finding all successive nodes and searching them +!=Ability Scores::3,5=! +(Will find cell in Row number 3 and Colum number 5 and insert the information contained there +in place of !=Ability Scores::3,5=! )External Namespace: !&Container::NodeName&! +-Can only be used from chat (currently) to call a node from anywhere in the gametree. You must +specify the container the node is in. You only have to specify the ‘largest’ container +(typically the one that shows in the gametree when fully collapsed). It doesn’t matter how +many smaller containers within the same container it’s in, you need only reference the +largest. *Note* Will not work if multiple nodes within the same container have the same name. +Multiple nodes within the entirety of the gametree can have the same names though as long as +they are in different containers. +-Uses the !&Container::NodeName&! syntax for normal nodes. +-Uses !&Container::NodeName::Row,Colum&! to reference cells within a grid. - Namespace Internal is completely context sensitive. You can assign a reference using the Namespace Internal method and it will always find the correct PC Sheet to search in. - -Namespace Internal must be used from within a node. +Examples: +!&3.5 Character Sheet::Strength&! +(Will find the node named “Strength” within the larger container “3.5 Character Sheet” and +insert it in place of !&3.5 Character Sheet::Strength&!) -Namespace External: -(Syntax) !&Top Node::Node&! +!&3.5 Character Sheet::Ability Scores::3,5&! +(Will find the cell in Row 3, Colum 5 in within the larger container “3.5 Character Sheet” and +insert its contents in place of !&3.5 Character Sheet::Ability Scores::3,5&!)Other Notes: +If you have similar nodes (i.e. have a lot of the same node names in them) located within the +same Larger container, Internal Namespace will still work as normal. With External Namespace, +you will have to specify which of the smaller containers you wish to call from. -Usage: Namespace External is a different approach to Namespace. With Namespace External you can use the syntax in chat or in other nodes to cross reference nodes. Instead of External being context sensitive, External uses a broadscope that you can narrow down. +For example, if you have a folder container that has two nodes in it, Internal will still work +fine from within either. However, if you are trying to use External, it you will have to +specify which of smaller containers you want like so: +!&LargerContainer::SmallerContainer::NodeName&! - It is really easy to narrow down External. External doesn't work like a string, it works like a lightning bolt. To get a good example open up the 4e PC Sheet node that comes with Traipse and try some different commands in chat. +I.E.: +The Largest container is called “Character Sheets.” It contains three other, Smaller +containers called “Luke,” “Leia,” and “Vader.” If you want to call the “Strength” node located +in “Leia” you will have to specify it like so: !&Character Sheets::Leia::Strength&!. The Namespace 2.0 is so far my greatest gift to OpenRPG. Namespace 2.0 surpasses the other Namespaces styles because it has a lightning bolt effect. + +In 1.7.1 you could use a reference such as !@Name@! to get the name of the Behir (Example Node). The biggest problem with the Namespace was it would only look at the top most node. + +Traipse changes how Namespace works by allowing users to be more specific without needing to be too specific. Namespace 2.0 works in a similar fashion, by finding the top most node with a similar name and attempting to use it. Yet, if you want to be more specific you can add node names to the reference and Namespace will find them in order. + +Below are some examples uses of the new Namespace. To try them out, create a 4e PC Sheet node and press the Send button. <b>1:</b> !&4e PC Sheet::Slot 1&! -<b>2:</b> !&4e PC Sheet::Belt:: Slot 1&! +<b>2:</b> !&4e PC Sheet::Belt::Slot 1&! <b>3:</b> !&4e PC Sheet::Inventory&! <b>4:</b> !&4e PC Sheet::Inventory::Slot 1&! Did you see what happened with the last two? Thankfully there is more than one way to get a node! -(Create a 4e PC Sheet node from the Templates and press Send ---v to try it) - - +(Create a 4e PC Sheet node from the Templates and press Send ---v to try it) + Grids can now be called from by adding a Row, Column to the end of the grid reference. Example: !&Abilities::2,2&! @@ -518,12 +562,14 @@ - - - + + + + + diff -r b29454610f36 -r 9230a33defd9 orpg/templates/nodes/4e_char_sheet.xml --- a/orpg/templates/nodes/4e_char_sheet.xml Mon May 03 03:29:14 2010 -0500 +++ b/orpg/templates/nodes/4e_char_sheet.xml Wed Jun 16 03:06:20 2010 -0500 @@ -32,27 +32,27 @@ This bears repeating: It comes with a Back Pack text node that you can clone to make bags and other containers. - - - + + + - + - - + + - + - + - + text @@ -104,7 +104,7 @@ Total !=AC Bonus::(3,2)=!+!=AC Bonus::(4,2)=! - Armor!!Armor::(2,2)!!Misc0 + Armor!=Armor::(2,2)=!Misc0 diff -r b29454610f36 -r 9230a33defd9 orpg/templates/nodes/Traipse_User_Guide.xml --- a/orpg/templates/nodes/Traipse_User_Guide.xml Mon May 03 03:29:14 2010 -0500 +++ b/orpg/templates/nodes/Traipse_User_Guide.xml Wed Jun 16 03:06:20 2010 -0500 @@ -1,5 +1,6 @@ - - Welcome to Traipse OpenRPG. + + + Welcome to Traipse OpenRPG. This small user manual should help users learn about the details of OpenRPG that are often times obscure. @@ -16,14 +17,19 @@ Adding to the Manual: Do you see something that could be explained eaiser? Report the problem as a bug and it will be added to the manual. - - The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few. + + + + The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few. The chat includes a set of commands. You can learn about the commands by entering /help The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text. - - The Tabs: + + + + + The Tabs: The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General. When you select one of the tabs you may access that map layer and it's settings. You may only select tabs based on your role. @@ -55,8 +61,100 @@ Fog: The fog layer hides the entire map from the prying eyes of players. - - Quick Help: + + + + Namespace 2.0 + +Internal Namespace: !=NodeName=! or !=GridName::Row,Colum=! +External Namespace: !&Container::NodeName&! or !&Container::GridName::Row,Colum&! + +Namespace 2.0 now has two different ways of finding nodes in your gametree: Internal and +External. The new version will find nodes differently based on which method you use. With External you start looking from the gametree but can define a "container" to be more specific. With Internal you start looking from the "node" the reference is in and look through the tree backwards. You can now reference cells within a grid using either. + +*An explanation of terms* +Gametree: The list of objects on the left-hand side of the window that holds all your nodes. +Node: Refers to any object in the gametree. +Container: Refers only to those nodes that are capable of storing other nodes (Splitter, +Tabbers, Folder, Forms, etc.). Used here, it usually refers to the largest container, i.e. the +one that shows up in the gametree when fully collapsed. A Container can contain other +containers. +Internal Namespace: !=NodeName=! +-Used from within a node to call another node in the same container, such as a list node +calling a text node or grid. *Note* Will not work if multiple nodes within the same container +have the same name. Multiple nodes within the entirety of the gametree can have the same names +though as long as they are in different containers. +-Uses the !=NodeName=! syntax for normal nodes. +-Uses !=GridName::Row,Colum=! to reference cells within a grid + +Examples: +!=Strength=! +(Will find the node named “Strength” in the same container and insert it in place of +!=Strength=!) + +!=Ability Scores::3,5=! +(Will find cell in Row number 3 and Colum number 5 and insert the information contained there +in place of !=Ability Scores::3,5=! )External Namespace: !&Container::NodeName&! +-Can only be used from chat (currently) to call a node from anywhere in the gametree. You must +specify the container the node is in. You only have to specify the ‘largest’ container +(typically the one that shows in the gametree when fully collapsed). It doesn’t matter how +many smaller containers within the same container it’s in, you need only reference the +largest. *Note* Will not work if multiple nodes within the same container have the same name. +Multiple nodes within the entirety of the gametree can have the same names though as long as +they are in different containers. +-Uses the !&Container::NodeName&! syntax for normal nodes. +-Uses !&Container::NodeName::Row,Colum&! to reference cells within a grid. + +Examples: +!&3.5 Character Sheet::Strength&! +(Will find the node named “Strength” within the larger container “3.5 Character Sheet” and +insert it in place of !&3.5 Character Sheet::Strength&!) + +!&3.5 Character Sheet::Ability Scores::3,5&! +(Will find the cell in Row 3, Colum 5 in within the larger container “3.5 Character Sheet” and +insert its contents in place of !&3.5 Character Sheet::Ability Scores::3,5&!)Other Notes: +If you have similar nodes (i.e. have a lot of the same node names in them) located within the +same Larger container, Internal Namespace will still work as normal. With External Namespace, +you will have to specify which of the smaller containers you wish to call from. + +For example, if you have a folder container that has two nodes in it, Internal will still work +fine from within either. However, if you are trying to use External, it you will have to +specify which of smaller containers you want like so: +!&LargerContainer::SmallerContainer::NodeName&! + +I.E.: +The Largest container is called “Character Sheets.” It contains three other, Smaller +containers called “Luke,” “Leia,” and “Vader.” If you want to call the “Strength” node located +in “Leia” you will have to specify it like so: !&Character Sheets::Leia::Strength&!. The Namespace 2.0 is so far my greatest gift to OpenRPG. Namespace 2.0 surpasses the other Namespaces styles because it has a lightning bolt effect. + +In 1.7.1 you could use a reference such as !@Name@! to get the name of the Behir (Example Node). The biggest problem with the Namespace was it would only look at the top most node. + +Traipse changes how Namespace works by allowing users to be more specific without needing to be too specific. Namespace 2.0 works in a similar fashion, by finding the top most node with a similar name and attempting to use it. Yet, if you want to be more specific you can add node names to the reference and Namespace will find them in order. + +I hope you enjoy the new Namespace very much. I tried to capture an OpenRPG users idea of how Namespace 'should' work and this time I think I set a new bar. I even created a plugin so Traipse users can use the Standard namespace references! + +Below are some examples uses of the new Namespace. To try them out, create a 4e PC Sheet node and press the Send button. + +<b>1:</b> !&4e PC Sheet::Slot 1&! +<b>2:</b> !&4e PC Sheet::Belt::Slot 1&! +<b>3:</b> !&4e PC Sheet::Inventory&! +<b>4:</b> !&4e PC Sheet::Inventory::Slot 1&! + + Did you see what happened with the last two? Thankfully there is more than one way to get a node! + +(Create a 4e PC Sheet node from the Templates and press Send ---v to try it) + + Grids can now be called from by adding a Row, Column to the end of the grid reference. + +Example: !&Abilities::2,2&! + + + Quick Help: + +Designer Note: +=== +For the life span of Ornery Orc the new Child, Parent, Root reference will exist, but in Pious the reference system will not transfer. This is because of the way the new Namespace works. Namespace will become the exclusive referencing system +=== The referencing system is an update to the Core of how the Game Tree works. In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further @@ -113,86 +211,69 @@ In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location. This freedom will help with future design and I feel it also frees up the hands of the GM who does not need to Index, un-Index, Namespace, un-Namspace the various creatures he or she may have in a Game Tree. - - <b>Root Reference</b> + + + <b>Root Reference</b> Works at the tree level. Must be exact. <b>Root Reference 1:</b> !@Reference Examples::Group::Child@! -<b>Root Reference 2:</b> !@Reference Examples::Grid::(2,1)@! - - <b>Grid Reference</b> +<b>Root Reference 2:</b> !@Reference Examples::Grid::2,1@! + + + <b>Grid Reference</b> Works by looking at the (Row, Column) of a Grid. -<b>Grid Reference 1:</b> !@Reference Examples::Grid::(1,1)@! -<b>Grid Reference 2:</b> !!Grid::(1,1)!! - - <b>Child Reference</b> +<b>Grid Reference 1:</b> !@Reference Examples::Grid::1,1@! +<b>Grid Reference 2:</b> !!Grid::1,1!! + + + <b>Child Reference</b> Works at the current tree location. <b>Child Reference 1:</b> !!Group::Child!! <b>Child Reference 2:</b> !!Group::Group_2::Child_2!! - - <b>Parent Reference</b> + + + <b>Parent Reference</b> Works by indexing the tree map of the node with the Reference. Allows you to start from a 'Parent'. <b>Parent Reference 1:</b> !!Group::Group_2::Child_2!! <b>Parent Reference 2:</b> !#Bonus Nodes::Deck::Draw#! - - - - !#Group::Child#! - - - !#Group::Child#! - - Child Node Data - - - - 0 - 0 - - - !!Group::Child!! - 0 - - - - - - With the new additions to the Game Tree using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended. - -Grid Nodes: - Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@! -The example will return the top left most cell data. The grid understands coordinates like this (Row, Column) - - Grid nodes can reference node data just like any other node can. With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll. While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. - - Here is an example with a 3 x 3 Grid -Example: !@Grid::([#1d3], [#1d3])@! - -The result will be a random event from the grid. - -Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52) - -List Nodes: - List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node. - - For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references. - -(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.) - - Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!! - -Text Nodes: - Text nodes remain little changed. I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes. - - Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes. - - Text nodes also work great when you need to have story text at hand that you don't want to type out during play. Create chapters with folder nodes and add the adventure text to different nodes. You can then use a List Node or a Grid Node to reference the different chapters. - -Bonus Node Included: A small book node with 1 Chapter and 3 Parts. Traipse node referencing is unlike other distributions of OpenRPG. The Game Tree mapping is a fluid map that changes with the location of your nodes. This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work. + + + + + !#Group::Child#! + + + + !#Group::Child#! + + + + + Child Node Data + + + + + + 0 + 0 + + + !!Group::Child!! + 0 + + + + + + + + + Traipse node referencing is unlike other distributions of OpenRPG. The Game Tree mapping is a fluid map that changes with the location of your nodes. This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work. (Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map) @@ -244,8 +325,46 @@ Examples: !@Kammen-Pai::Cast::Ray of Frost@! -!@Kammen-Pai::Feat::Ability Focus@! - In Traipse starting a server has never been easier. The setup is as easy as 1., 2., 3 +!@Kammen-Pai::Feat::Ability Focus@! + + + With the new additions to the Game Tree using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended. + +Grid Nodes: + Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@! +The example will return the top left most cell data. The grid understands coordinates like this (Row, Column) + + Grid nodes can reference node data just like any other node can. With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll. While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. + + Here is an example with a 3 x 3 Grid +Example: !@Grid::([#1d3], [#1d3])@! + +The result will be a random event from the grid. + +Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52) + +List Nodes: + List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node. + + For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references. + +(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.) + + Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!! + +Text Nodes: + Text nodes remain little changed. I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes. + + Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes. + + Text nodes also work great when you need to have story text at hand that you don't want to type out during play. Create chapters with folder nodes and add the adventure text to different nodes. You can then use a List Node or a Grid Node to reference the different chapters. + +Bonus Node Included: A small book node with 1 Chapter and 3 Parts. + + + + + In Traipse starting a server has never been easier. The setup is as easy as 1., 2., 3 1. You will need to first start the Server GUI or the basic text based Server at least once so your software creates the server_ini.xml files in your myfiles directory. You can start it once and quit. @@ -256,10 +375,15 @@ 3. This is the hardest step. You need to make sure your selected port is forwarded by your router and open to your firewall. That's it! You can now start the server and register it to the meta for all users to enjoy! - - - - - - - \ No newline at end of file + + + + + + + + + + + + \ No newline at end of file diff -r b29454610f36 -r 9230a33defd9 orpg/templates/nodes/Warhammerv2CS2-Traipse.xml --- a/orpg/templates/nodes/Warhammerv2CS2-Traipse.xml Mon May 03 03:29:14 2010 -0500 +++ b/orpg/templates/nodes/Warhammerv2CS2-Traipse.xml Wed Jun 16 03:06:20 2010 -0500 @@ -1,71 +1,69 @@ - - -
- + + + - + - + - + - + - - + + 1 - + - + - + - + 1 - + - + - + - + Meduim - + - + - + - - - + + - + - + - + Copper @@ -93,227 +91,216 @@ - - - + + [1d20 + (!=Character Level=! / 2) + ((!=Ability Init=! / 2) - 5) + !=Feat Init Bonus=! + !=Misc Init Bonus=!] - + 6 - - - - + + + !=Dexterity=! - + 0 - + 0 - - - + + 6 - + 0 - + 0 - + 0 - + [!=Racial Speed Base=! + !=Armor Speed Bonus=! + !=Item Speed Bonus=! + !=Misc Speed Bonus=!] - - - + + 10 - + 10 - + 10 - + 10 - + 10 - + 10 - - - - - - - - + + + + + + + + - - - + + 10 - + 10 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + 0 - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + 0 - - - - - + + + Maximum Health @@ -360,7 +347,7 @@ - + Armor Class @@ -384,694 +371,652 @@ - - [1d20 + !=Class Save Bonus=! + !=Racial Save Bonus=! + !=Feat Save Bonus=! + !=Misc Save Bonus=!] + + [1d20 + !=Class Save Bonus=! + !=Racial Save Bonus=! + !=Feat Save Bonus=! + !=Misc Save Bonus=!] - - - - + + + 0 - + 0 - + 0 - + 0 - - - + + 0 - + !=Dexterity=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=AC Ability=! / 2) - 5) + !=Class AC Bonus=! + !=Feat AC Bonus=! + !=Equipment AC Bonus=! + !=Misc AC Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=AC Ability=! / 2) - 5) + !=Class AC Bonus=! + !=Feat AC Bonus=! + !=Equipment AC Bonus=! + !=Misc AC Bonus=!] - - - + + 0 - + !=Strength=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Fort Ability=! / 2) - 5) + !=Class Fort Bonus=! + !=Feat Fort Bonus=! + !=Equipment Fort Bonus=! + !=Misc Fort Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Fort Ability=! / 2) - 5) + !=Class Fort Bonus=! + !=Feat Fort Bonus=! + !=Equipment Fort Bonus=! + !=Misc Fort Bonus=!] - - - + + 0 - + !=Dexterity=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Ref Ability=! / 2) - 5) + !=Class Ref Bonus=! + !=Feat Ref Bonus=! + !=Equipment Ref Bonus=! + !=Misc Ref Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Ref Ability=! / 2) - 5) + !=Class Ref Bonus=! + !=Feat Ref Bonus=! + !=Equipment Ref Bonus=! + !=Misc Ref Bonus=!] - - - + + 0 - + !=Wisdom=! - + 0 - + 0 - + 0 - - [10 + (!=Character Level=! / 2) + ((!=Will Ability=! / 2) - 5) + !=Class Will Bonus=! + !=Feat Will Bonus=! + !=Equipment Will Bonus=! + !=Misc Will Bonus=!] + + [10 + (!=Character Level=! / 2) + ((!=Will Ability=! / 2) - 5) + !=Class Will Bonus=! + !=Feat Will Bonus=! + !=Equipment Will Bonus=! + !=Misc Will Bonus=!] - - - - + + + Weapon 1 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Melee Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] - - + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Melee Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Melee Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Range Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] - - + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Range Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Range Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Charge Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=! + !=Weapon 1 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 1 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 1 Attack Class and Feat Bonus=! + !=Weapon 1 Attack Proficiency Bonus=! + ((!=Weapon 1 Charge Attack Ability=! / 2) - 5) + !=Weapon 1 Attack Misc Bonus=! + !=Weapon 1 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!)**std(!=Weapon 1 Damage Dice Sides=!)) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] - - - !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] + + !=Weapon 1 Name=!: [Q((!=Weapon 1 Damage Multiplier=!*!=Weapon 1 Damage Dice Count=!)d!=Weapon 1 Damage Dice Sides=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] + + + !=Weapon 1 Name=! = [Q(!=Weapon 1 Damage Multiplier=! * !=Weapon 1 Damage Dice Count=!*!=Weapon 1 Damage Dice Sides=!) + (!=Weapon 1 Critical Extra Damage=!) + !=Weapon 1 Damage Feat Bonus=! + ((!=Weapon 1 Charge Damage Ability=! / 2) - 5) + !=Weapon 1 Damage Misc Bonus=! + !=Weapon 1 Charge Damage Bonus=!] - - - + + Weapon 2 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Melee Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] - - + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Melee Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Melee Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Range Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] - - + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Range Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Range Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Charge Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=! + !=Weapon 2 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 2 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 2 Attack Class and Feat Bonus=! + !=Weapon 2 Attack Proficiency Bonus=! + ((!=Weapon 2 Charge Attack Ability=! / 2) - 5) + !=Weapon 2 Attack Misc Bonus=! + !=Weapon 2 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!)**std(!=Weapon 2 Damage Dice Sides=!)) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] - - - !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] + + !=Weapon 2 Name=!: [Q((!=Weapon 2 Damage Multiplier=!*!=Weapon 2 Damage Dice Count=!)d!=Weapon 2 Damage Dice Sides=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] + + + !=Weapon 2 Name=! = [Q(!=Weapon 2 Damage Multiplier=! * !=Weapon 2 Damage Dice Count=!*!=Weapon 2 Damage Dice Sides=!) + (!=Weapon 2 Critical Extra Damage=!) + !=Weapon 2 Damage Feat Bonus=! + ((!=Weapon 2 Charge Damage Ability=! / 2) - 5) + !=Weapon 2 Damage Misc Bonus=! + !=Weapon 2 Charge Damage Bonus=!] - - - + + Weapon 3 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Melee Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] - - + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Melee Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Melee Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Range Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] - - + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Range Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Range Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Charge Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=! + !=Weapon 3 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 3 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 3 Attack Class and Feat Bonus=! + !=Weapon 3 Attack Proficiency Bonus=! + ((!=Weapon 3 Charge Attack Ability=! / 2) - 5) + !=Weapon 3 Attack Misc Bonus=! + !=Weapon 3 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!)**std(!=Weapon 3 Damage Dice Sides=!)) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] - - - !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] + + !=Weapon 3 Name=!: [Q((!=Weapon 3 Damage Multiplier=!*!=Weapon 3 Damage Dice Count=!)d!=Weapon 3 Damage Dice Sides=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] + + + !=Weapon 3 Name=! = [Q(!=Weapon 3 Damage Multiplier=! * !=Weapon 3 Damage Dice Count=!*!=Weapon 3 Damage Dice Sides=!) + (!=Weapon 3 Critical Extra Damage=!) + !=Weapon 3 Damage Feat Bonus=! + ((!=Weapon 3 Charge Damage Ability=! / 2) - 5) + !=Weapon 3 Damage Misc Bonus=! + !=Weapon 3 Charge Damage Bonus=!] - - - + + Weapon 4 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Melee Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] - - + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Melee Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Melee Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Range Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] - - + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Range Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Range Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Charge Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=! + !=Weapon 4 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 4 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 4 Attack Class and Feat Bonus=! + !=Weapon 4 Attack Proficiency Bonus=! + ((!=Weapon 4 Charge Attack Ability=! / 2) - 5) + !=Weapon 4 Attack Misc Bonus=! + !=Weapon 4 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!)**std(!=Weapon 4 Damage Dice Sides=!)) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] - - - !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] + + !=Weapon 4 Name=!: [Q((!=Weapon 4 Damage Multiplier=!*!=Weapon 4 Damage Dice Count=!)d!=Weapon 4 Damage Dice Sides=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] + + + !=Weapon 4 Name=! = [Q(!=Weapon 4 Damage Multiplier=! * !=Weapon 4 Damage Dice Count=!*!=Weapon 4 Damage Dice Sides=!) + (!=Weapon 4 Critical Extra Damage=!) + !=Weapon 4 Damage Feat Bonus=! + ((!=Weapon 4 Charge Damage Ability=! / 2) - 5) + !=Weapon 4 Damage Misc Bonus=! + !=Weapon 4 Charge Damage Bonus=!] - - - + + Weapon 5 Name - - - - - 0 - - - 0 - - + + + + 0 + + + 0 + + 0 - - - - 0 - - - 0 - - + + + 0 + + + 0 + + 1 - + 4 - + 1 - + 0 - - - - + + + !=Strength=! - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Melee Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] - - + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Melee Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] + + !=Strength=! - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Melee Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - + + !=Dexterity=! - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Range Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] - - + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Range Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=!] + + !=Dexterity=! - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Range Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=!] - - - + + !=Strength=! - - 0 - - - !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Charge Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=! + !=Weapon 5 Charge Attack Bonus=!] - - + + 0 + + + !=Weapon 5 Name=!: [Q1d20 + (!=Character Level=! / 2) + !=Weapon 5 Attack Class and Feat Bonus=! + !=Weapon 5 Attack Proficiency Bonus=! + ((!=Weapon 5 Charge Attack Ability=! / 2) - 5) + !=Weapon 5 Attack Misc Bonus=! + !=Weapon 5 Charge Attack Bonus=!] + + !=Strength=! - + 1 - - !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!)**std(!=Weapon 5 Damage Dice Sides=!)) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] - - - !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] + + !=Weapon 5 Name=!: [Q((!=Weapon 5 Damage Multiplier=!*!=Weapon 5 Damage Dice Count=!)d!=Weapon 5 Damage Dice Sides=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] + + + !=Weapon 5 Name=! = [Q(!=Weapon 5 Damage Multiplier=! * !=Weapon 5 Damage Dice Count=!*!=Weapon 5 Damage Dice Sides=!) + (!=Weapon 5 Critical Extra Damage=!) + !=Weapon 5 Damage Feat Bonus=! + ((!=Weapon 5 Charge Damage Ability=! / 2) - 5) + !=Weapon 5 Damage Misc Bonus=! + !=Weapon 5 Charge Damage Bonus=!] - - - - - - - 0 - - - 0 - - + + + + + 0 + + + 0 + + 0 - - - - + + + !=Strength=! - - 0 - - - Bull Rush: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Rush Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Rush Attack Bonus=!] + + 0 + + + Bull Rush: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Rush Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Rush Attack Bonus=!] - - - + + !=Strength=! - - 0 - - - Grab: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Grab Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Grab Attack Bonus=!] + + 0 + + + Grab: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Grab Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Grab Attack Bonus=!] - - - + + !=Strength=! - - 0 - - + + 0 + + Fortitude - - Escape: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Escape Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Escape Attack Bonus=!] vs. !=Unarmed Escape Target Defense=! + + Escape: [Q1d20 + (!=Character Level=! / 2) + !=Unarmed Attack Class and Feat Bonus=! + !=Unarmed Attack Proficiency Bonus=! + ((!=Unarmed Escape Attack Ability=! / 2) - 5) + !=Unarmed Attack Misc Bonus=! + !=Unarmed Escape Attack Bonus=!] vs. !=Unarmed Escape Target Defense=! - - - - - + + + 1 - + Power Name @@ -1138,7 +1083,7 @@ - + Power Name @@ -1195,7 +1140,7 @@ - + Power Name @@ -1263,4914 +1208,5387 @@ - - - - - + + + + At-Will 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - + /me uses power !=At-Will 1 Name=! - - - + + At-Will 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - + /me uses power !=At-Will 2 Name=! - - - + + At-Will 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - + /me uses power !=At-Will 3 Name=! - - - + + At-Will 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - + /me uses power !=At-Will 4 Name=! - - - + + At-Will 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - + /me uses power !=At-Will 5 Name=! - - - + + At-Will 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - + /me uses power !=At-Will 6 Name=! - - - + + At-Will 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - + /me uses power !=At-Will 7 Name=! - - - + + At-Will 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - + /me uses power !=At-Will 8 Name=! - - - + + At-Will 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - + /me uses power !=At-Will 9 Name=! - - - - + + + Encounter 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - + /me uses power !=Encounter 1 Name=! - - - + + Encounter 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - + /me uses power !=Encounter 2 Name=! - - - + + Encounter 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - + /me uses power !=Encounter 3 Name=! - - - + + Encounter 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - + /me uses power !=Encounter 4 Name=! - - - + + Encounter 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - + /me uses power !=Encounter 5 Name=! - - - + + Encounter 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - + /me uses power !=Encounter 6 Name=! - - - + + Encounter 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - + /me uses power !=Encounter 7 Name=! - - - + + Encounter 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - + /me uses power !=Encounter 8 Name=! - - - + + Encounter 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - + /me uses power !=Encounter 9 Name=! - - - - - + + + Daily 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - + /me uses power !=Daily 1 Name=! - - - + + Daily 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - + /me uses power !=Daily 2 Name=! - - - + + Daily 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - + /me uses power !=Daily 3 Name=! - - - + + Daily 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - + /me uses power !=Daily 4 Name=! - - - + + Daily 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - + /me uses power !=Daily 5 Name=! - - - + + Daily 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - + /me uses power !=Daily 6 Name=! - - - + + Daily 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - + /me uses power !=Daily 7 Name=! - - - + + Daily 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - + /me uses power !=Daily 8 Name=! - - - + + Daily 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + 0 - + 1 - + 0 - + 6 - - - + + 1 - + 1 - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - + /me uses power !=Daily 9 Name=! - - - - - + + + Utility 1 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! + + + /me uses power !=Utility 1 Name=! - - - + + Utility 2 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + AC - + + !=Strength=! + + + 0 + + !=Strength=! - - 0 - - - !=Strength=! - - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! + + + /me uses power !=Utility 2 Name=! - - - + + Utility 3 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! + + + /me uses power !=Utility 3 Name=! - - - + + Utility 4 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! + + + /me uses power !=Utility 4 Name=! - - - + + Utility 5 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! + + + /me uses power !=Utility 5 Name=! - - - + + Utility 6 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! + + + /me uses power !=Utility 6 Name=! - - - + + Utility 7 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! + + + /me uses power !=Utility 7 Name=! - - - + + Utility 8 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! + + + /me uses power !=Utility 8 Name=! - - - + + Utility 9 Name - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AC - + !=Strength=! - - 0 - - + + 0 + + !=Strength=! - - 0 - - - - - + + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + 1 + + 1 - - 0 - - - 6 - - - - - - 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! + + + /me uses power !=Utility 9 Name=! - - - - + + - + - + - + @@ -6266,9 +6684,8 @@ - - - + + Player Name @@ -6315,7 +6732,7 @@ - + Maximum Health @@ -6370,7 +6787,7 @@ - + @@ -6393,7 +6810,7 @@ - + 10 @@ -6470,7 +6887,7 @@ - + 10 @@ -6484,7 +6901,7 @@ - + 0 @@ -6492,7 +6909,7 @@ - + 0 @@ -6500,7 +6917,7 @@ - + 0 @@ -6508,7 +6925,7 @@ - + 0 @@ -6518,71 +6935,69 @@ - - - - + + + Attack 1 Name - + 0 - - !=Attack 1 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 1 Bonus=!] + + !=Attack 1 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 1 Bonus=!] - + !=Strength=! - + 0 - + 1 - + 4 - + 0 - - !=Attack 1 Name=!: [Q(!=Attack 1 Damage Dice Count=!d!=Attack 1 Damage Dice Sides=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] + + !=Attack 1 Name=!: [Q(!=Attack 1 Damage Dice Count=!d!=Attack 1 Damage Dice Sides=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] - - !=Attack 1 Name=! = [Q(!=Attack 1 Damage Dice Count=!*!=Attack 1 Damage Dice Sides=!) + (!=Attack 1 Critical Extra Damage=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] + + !=Attack 1 Name=! = [Q(!=Attack 1 Damage Dice Count=!*!=Attack 1 Damage Dice Sides=!) + (!=Attack 1 Critical Extra Damage=!) + ((!=Attack 1 Damage Ability=! / 2) - 5) + !=Attack 1 Damage Other Bonus=!] - - - + + Attack 2 Name - + 0 - - !=Attack 2 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 2 Bonus=!] + + !=Attack 2 Name=!: [Q1d20 + !=Companion Level=! + !=Attack 2 Bonus=!] - + !=Strength=! - + 0 - + 1 - + 4 - + 0 - - !=Attack 2 Name=!: [Q(!=Attack 2 Damage Dice Count=!d!=Attack 2 Damage Dice Sides=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] + + !=Attack 2 Name=!: [Q(!=Attack 2 Damage Dice Count=!d!=Attack 2 Damage Dice Sides=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] - - !=Attack 2 Name=! = [Q(!=Attack 2 Damage Dice Count=!*!=Attack 2 Damage Dice Sides=!) + (!=Attack 2 Critical Extra Damage=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] + + !=Attack 2 Name=! = [Q(!=Attack 2 Damage Dice Count=!*!=Attack 2 Damage Dice Sides=!) + (!=Attack 2 Critical Extra Damage=!) + ((!=Attack 2 Damage Ability=! / 2) - 5) + !=Attack 2 Damage Other Bonus=!] diff -r b29454610f36 -r 9230a33defd9 orpg/tools/FlatNotebook.py --- a/orpg/tools/FlatNotebook.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/tools/FlatNotebook.py Wed Jun 16 03:06:20 2010 -0500 @@ -74,6 +74,7 @@ # Beginning Of FLATNOTEBOOK wxPython Code #---------------------------------------------------------------------- +print 'Flatnotebook' import wx import random import math diff -r b29454610f36 -r 9230a33defd9 orpg/tools/InterParse.py --- a/orpg/tools/InterParse.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/tools/InterParse.py Wed Jun 16 03:06:20 2010 -0500 @@ -49,7 +49,7 @@ s = self.NameSpaceE(s) s = self.NameSpaceI(s, node) s = self.NodeMap(s, node) - s = self.NodeParent(s, node.get('map')) + s = self.NodeParent(s, node) return s def Normalize(self, s, tab): @@ -159,7 +159,8 @@ namespace -- TaS, Prof. Ebral""" reg2 = re.compile("(!=(.*?)=!)") matches = reg1.findall(s) + reg2.findall(s) - tree_map = node.get('map') + try: tree_map = node.get('map') + except: return node for i in xrange(0,len(matches)): ## Build the new tree_map new_map = tree_map.split('::') @@ -168,7 +169,8 @@ node = self.get_node(new_map) newstr = self.LocationCheck(node, tree_map, new_map, find) s = s.replace(matches[i][0], newstr, 1) - s = self.ParseLogic(s, node) + s = self.NodeMap(s, node) + s = self.NodeParent(s, node) return s def NameSpaceE(self, s): @@ -231,8 +233,10 @@ s = self.NodeParent(s, tree_map) return s - def NodeParent(self, s, tree_map): + def NodeParent(self, s, node): """Parses player input for embedded nodes rolls""" + if node == 'Invalid Reference!': return node + tree_map = node.get('map') cur_loc = 0 reg = re.compile("(!#(.*?)#!)") matches = reg.findall(s) diff -r b29454610f36 -r 9230a33defd9 orpg/tools/orpg_settings.py --- a/orpg/tools/orpg_settings.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/tools/orpg_settings.py Wed Jun 16 03:06:20 2010 -0500 @@ -33,7 +33,8 @@ from orpg.tools.orpg_log import logger from orpg.tools.validate import validate -from orpg.orpg_xml import xml +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring from orpg.tools.settings import settings class orpgSettingsWnd(wx.Dialog): @@ -70,29 +71,28 @@ def build_gui(self): validate.config_file("settings.xml","default_settings.xml") filename = dir_struct["user"] + "settings.xml" - temp_file = open(filename) - temp_file.close() - children = self.settings.xml_dom._get_childNodes() - for c in children: self.build_window(c,self.tabber) + temp_file = parse(filename) + children = self.settings.xml_dom.getchildren() + for c in children: self.build_window(c, self.tabber) def build_window(self, xml_dom, parent_wnd): - name = xml_dom._get_nodeName() + name = xml_dom.tag #container = 0 if name=="tab": temp_wnd = self.do_tab_window(xml_dom,parent_wnd) return temp_wnd def do_tab_window(self, xml_dom, parent_wnd): - type = xml_dom.getAttribute("type") - name = xml_dom.getAttribute("name") + type = xml_dom.get("type") + name = xml_dom.get("name") if type == "grid": temp_wnd = self.do_grid_tab(xml_dom, parent_wnd) parent_wnd.AddPage(temp_wnd, name, False) elif type == "tab": temp_wnd = orpgTabberWnd(parent_wnd, style=FNB.FNB_NO_X_BUTTON) - children = xml_dom._get_childNodes() + children = xml_dom.getchildren() for c in children: - if c._get_nodeName() == "tab": self.do_tab_window(c, temp_wnd) + if c.tag == "tab": self.do_tab_window(c, temp_wnd) temp_wnd.SetSelection(0) parent_wnd.AddPage(temp_wnd, name, False) elif type == "text": @@ -103,12 +103,12 @@ def do_grid_tab(self, xml_dom, parent_wnd): settings = [] - children = xml_dom._get_childNodes() + children = xml_dom.getchildren() for c in children: - name = c._get_nodeName() - value = c.getAttribute("value") - help = c.getAttribute("help") - options = c.getAttribute("options") + name = c.tag + value = c.get("value") + help = c.get("help") + options = c.get("options") settings.append([name, value, options, help]) temp_wnd = settings_grid(parent_wnd, settings, self.changes) return temp_wnd @@ -309,4 +309,3 @@ for i in range(0,cols): self.SetColSize(i,col_w) self.Refresh() -#settings = orpg.tools.settings.Settings() diff -r b29454610f36 -r 9230a33defd9 orpg/tools/scriptkit.py --- a/orpg/tools/scriptkit.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/tools/scriptkit.py Wed Jun 16 03:06:20 2010 -0500 @@ -30,7 +30,7 @@ import time from orpg.orpg_windows import * -from orpg.orpg_xml import * +#from orpg.orpg_xml import * from orpg.orpg_wx import * import orpg.chat.chat_msg @@ -45,7 +45,7 @@ self.map = component.get( 'map' ) self.settings = component.get( 'settings' ) self.session = component.get('session') - self.xml = component.get('xml') + #self.xml = component.get('xml') def addMiniatureToMap( self, min_label, min_url, unique=0 ): """Adds a new miniature icon to the map. Miniature will be labeled unless autolabel is diff -r b29454610f36 -r 9230a33defd9 orpg/tools/settings.py --- a/orpg/tools/settings.py Mon May 03 03:29:14 2010 -0500 +++ b/orpg/tools/settings.py Wed Jun 16 03:06:20 2010 -0500 @@ -2,41 +2,32 @@ from orpg.tools.orpg_log import logger from orpg.tools.validate import validate -from orpg.orpg_xml import xml +from xml.etree.ElementTree import ElementTree, Element, parse +from xml.etree.ElementTree import fromstring, tostring from orpg.orpgCore import component from orpg.dirpath import dir_struct class Settings: def __init__(self): - self.xml = component.get("xml") self.changes = [] validate.config_file("settings.xml","default_settings.xml") self.filename = dir_struct["user"] + "settings.xml" - temp_file = open(self.filename) - txt = temp_file.read() - temp_file.close() - - self.xml_dom = xml.parseXml(txt) - - if self.xml_dom is None: self.rebuildSettings() - self.xml_dom = self.xml_dom._get_documentElement() + xml_dom = parse(dir_struct["user"] + "settings.xml") + if xml_dom == None: self.rebuildSettings() + else: self.xml_dom = xml_dom.getroot() def rebuildSettings(self): logger.info("Settings file has be corrupted, rebuilding settings.", True) try: os.remove(self.filename) except: pass - validate.config_file("settings.xml","default_settings.xml") - temp_file = open(self.filename) - txt = temp_file.read() - temp_file.close() - self.xml_dom = xml.parseXml(txt) + self.xml_dom = parse(self.filename).getroot() def get_setting(self, name): ##Depricated return self.get(name) def get(self, name): - try: return self.xml_dom.getElementsByTagName(name)[0].getAttribute("value") + try: return self.xml_dom.getiterator(name)[0].get("value") except: return 0 def get_setting_keys(self): ##Depricated @@ -44,30 +35,30 @@ def get_keys(self): keys = [] - tabs = self.xml_dom.getElementsByTagName("tab") + tabs = self.xml_dom.getiterator("tab") for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("type") == 'grid': - children = tabs[i]._get_childNodes() - for c in children: keys.append(c._get_tagName()) + if tabs[i].get("type") == 'grid': + children = tabs[i].getchildren() + for c in children: keys.append(c.tag) return keys def set_setting(self, name, value): ##Depricated self.change(name, value) def change(self, name, value): - self.xml_dom.getElementsByTagName(name)[0].setAttribute("value", value) + self.xml_dom.getiterator(name)[0].set("value", value) def add_setting(self, tab, setting, value, options, help): ##Depricated return self.add(tab, setting, value, options, help) def add(self, tab, setting, value, options, help): - if len(self.xml_dom.getElementsByTagName(setting)) > 0: return False - tabs = self.xml_dom.getElementsByTagName("tab") - newsetting = xml.parseXml('<' + setting + ' value="' + value + '" options="' + - options + '" help="' + help + '" />')._get_documentElement() + if len(self.xml_dom.getiterator(setting)) > 0: return False + tabs = self.xml_dom.getiterator("tab") + newsetting = fromstring('<' + setting + ' value="' + value + '" options="' + + options + '" help="' + help + '" />') for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("name") == tab and tabs[i].getAttribute("type") == 'grid': - tabs[i].appendChild(newsetting) + if tabs[i].get("name") == tab and tabs[i].get("type") == 'grid': + tabs[i].append(newsetting) return True return False @@ -75,49 +66,44 @@ tab_xml = '' else: tab_xml += 'name="' + tabname + '" type="' + tabtype + '">' - newtab = xml.parseXml(tab_xml)._get_documentElement() + newtab = fromstring(tab_xml) if parent != None: - tabs = self.xml_dom.getElementsByTagName("tab") + tabs = self.xml_dom.getiterator("tab") for i in xrange(0, len(tabs)): - if tabs[i].getAttribute("name") == parent and tabs[i].getAttribute("type") == 'tab': - children = tabs[i]._get_childNodes() + if tabs[i].get("name") == parent and tabs[i].get("type") == 'tab': + children = tabs[i].getchildren() for c in children: - if c.getAttribute("name") == tabname: return False - tabs[i].appendChild(newtab) + if c.get("name") == tabname: return False + tabs[i].append(newtab) return True else: - children = self.xml_dom._get_childNodes() + children = self.xml_dom.getchildren() for c in children: - if c.getAttribute("name") == tabname: return False - self.xml_dom.appendChild(newtab) + if c.get("name") == tabname: return False + self.xml_dom.append(newtab) return True return False def updateIni(self): defaultFile = orpg.dirpath.dir_struct['template'] + 'default_settings.xml' - temp_file = open(defaultFile) - txt = temp_file.read() - temp_file.close() - default_dom = xml.parseXml(txt)._get_documentElement() - for child in default_dom.getChildren(): - if child._get_tagName() == 'tab' and child.hasChildNodes(): self.proccessChildren(child) - default_dom.unlink() + default_dom = parse(defaultfile) + for child in default_dom.getchildren(): + if child.tag == 'tab': self.proccessChildren(child) def proccessChildren(self, dom, parent=None): - if dom._get_tagName() == 'tab': - self.add_tab(parent, dom.getAttribute("name"), dom.getAttribute("type")) + if dom.tag == 'tab': self.add_tab(parent, dom.get("name"), dom.get("type")) - for child in dom.getChildren(): - if child._get_tagName() == 'tab' and child.hasChildNodes(): - self.proccessChildren(child, dom.getAttribute("name")) + for child in dom.getchildren(): + if child.tag == 'tab': self.proccessChildren(child, dom.get("name")) else: - self.add_setting(dom.getAttribute("name"), child._get_tagName(), - child.getAttribute("value"), child.getAttribute("options"), - child.getAttribute("help")) + self.add_setting(dom.get("name"), child.tag, + child.get("value"), child.get("options"), + child.get("help")) def save(self): + #self.xml_dom.write(self.filename) temp_file = open(self.filename, "w") - temp_file.write(xml.toxml(self.xml_dom,1)) + temp_file.write(tostring(self.xml_dom)) temp_file.close() settings = Settings() diff -r b29454610f36 -r 9230a33defd9 upmana/updatemana.py --- a/upmana/updatemana.py Mon May 03 03:29:14 2010 -0500 +++ b/upmana/updatemana.py Wed Jun 16 03:06:20 2010 -0500 @@ -160,7 +160,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def Finish(self, evt=None): @@ -194,7 +194,7 @@ for t in types: self.btnName = str(t) self.btn[self.id] = wx.RadioButton(dlg, wx.ID_ANY, str(t), name=self.btnName) - if self.btnName == self.current: self.btn[self.id].SetValue(True) + if self.btnName == self.current: self.btn[self.id].SetValue(True); self.current_id = self.id self.btnlist[self.id] = self.btnName dlgsizer.Add(self.btn[self.id], (row, col)) col += 1; self.id += 1 @@ -212,7 +212,16 @@ def PackageSet(self, event): for btn in self.btn: - if self.btn[btn].GetValue() == True: self.current = self.btnlist[btn] + if self.btn[btn].GetValue() == True: + if self.btnlist[btn] == 'pious-paladin': + try: from PyQt4 import QtCore + except: + error = "'Pious Paladin' requires PyQt 4.6. For stability you will not be able to update." + dlg = wx.MessageDialog(None, error, 'Failed PyQt Test', wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + self.btn[self.current_id].SetValue(True) + self.current = self.btnlist[self.current_id] + else: self.current = self.btnlist[btn] branches = self.repo.branchtags() heads = dict.fromkeys(self.repo.heads(), 1) @@ -622,7 +631,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def get_packages(self, type=None): @@ -818,7 +827,7 @@ manifest = open(self.filename) self.ignorelist = [] ignore = manifest.readlines() - for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1])) + for i in ignore: self.ignorelist.append(str(i[:len(i)-1])) manifest.close() def OnExit(self):
LabelImageURLUnique