changeset 227:81d0bfd5e800 alpha

Traipse Alpha 'OpenRPG' {100612-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Preparing to close updates) New Features: New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order Fixes: Fix to InterParse that was causing an Infernal Loop with Namespace Internal Fix to XML data, removed old Minidom and switched to Element Tree Fix to Server that was causing eternal attempt to find a Server ID, in Register Rooms thread Fix to metaservers.xml file not being created
author sirebral
date Sat, 12 Jun 2010 03:50:37 -0500
parents 4b2884f29a72
children
files orpg/chat/chat_msg.py orpg/chat/chatwnd.py orpg/chat/commands.py orpg/dieroller/base.py orpg/dieroller/rollers/7sea.py orpg/dieroller/rollers/__init__.py orpg/dieroller/rollers/alternity.py orpg/dieroller/rollers/d20.py orpg/dieroller/rollers/gurps.py orpg/dieroller/rollers/hackmaster.py orpg/dieroller/rollers/hero.py orpg/dieroller/rollers/mythos.py orpg/dieroller/rollers/runequest.py orpg/dieroller/rollers/savage.py orpg/dieroller/rollers/std.py orpg/dieroller/rollers/trinity.py orpg/dieroller/rollers/wfrpg.py orpg/dieroller/rollers/wod.py orpg/dieroller/rollers/wodex.py orpg/dieroller/utils.py orpg/gametree/gametree.py orpg/gametree/nodehandlers/StarWarsd20.py orpg/gametree/nodehandlers/chatmacro.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/core.py orpg/gametree/nodehandlers/d20.py orpg/gametree/nodehandlers/dnd3e.py orpg/gametree/nodehandlers/forms.py orpg/gametree/nodehandlers/map_miniature_nodehandler.py orpg/gametree/nodehandlers/minilib.py orpg/gametree/nodehandlers/rpg_grid.py orpg/gametree/nodehandlers/voxchat.py orpg/main.py orpg/mapper/background.py orpg/mapper/background_handler.py orpg/mapper/background_msg.py orpg/mapper/base.py orpg/mapper/base_handler.py orpg/mapper/base_msg.py orpg/mapper/fog.py orpg/mapper/fog_msg.py orpg/mapper/grid.py orpg/mapper/grid_handler.py orpg/mapper/grid_msg.py orpg/mapper/images.py orpg/mapper/map.py orpg/mapper/map_handler.py orpg/mapper/map_msg.py orpg/mapper/map_prop_dialog.py orpg/mapper/min_dialogs.py orpg/mapper/miniatures.py orpg/mapper/miniatures_handler.py orpg/mapper/miniatures_msg.py orpg/mapper/region.py orpg/mapper/whiteboard.py orpg/mapper/whiteboard_handler.py orpg/mapper/whiteboard_msg.py orpg/networking/gsclient.py orpg/networking/meta_server_lib.py orpg/networking/mplay_client.py orpg/networking/mplay_messaging.py orpg/networking/mplay_server.py orpg/networking/mplay_server_gui.py orpg/orpg_version.py orpg/orpg_windows.py orpg/orpg_xml.py orpg/player_list.py orpg/pluginhandler.py orpg/templates/default_LobbyMessage.html orpg/templates/default_Lobby_map.xml orpg/templates/default_settings.xml orpg/templates/feature.xml orpg/templates/nodes/4e_char_sheet.xml orpg/templates/nodes/split.xml orpg/templates/nodes/textctrl.xml orpg/tools/FlatNotebook.py orpg/tools/aliaslib.py orpg/tools/inputValidator.py orpg/tools/orpg_log.py orpg/tools/orpg_settings.py orpg/tools/passtool.py orpg/tools/predTextCtrl.py orpg/tools/pubsub.py orpg/tools/rgbhex.py orpg/tools/scriptkit.py orpg/tools/server_probe.py orpg/tools/settings.py orpg/tools/toolBars.py orpg/tools/validate.py plugins/bcg/__init__.py plugins/bcg/tok_dialogs.py plugins/bcg/token_handler.py plugins/bcg/tokens.py plugins/bcg/tokens_msg.py plugins/cherrypy/License.txt plugins/xxbcg.py plugins/xxblank.py plugins/xxchatnotify.py plugins/xxgsc.py plugins/xxhiddendice.py plugins/xxmouse-zoom.py plugins/xxsimpleinit.py plugins/xxspell.py plugins/xxstdnamespace.py plugins/xxurl2link.py readme.txt start_noupdate.py upmana/updatemana.py upmana/validate.py
diffstat 108 files changed, 2608 insertions(+), 5417 deletions(-) [+]
line wrap: on
line diff
--- a/orpg/chat/chat_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/chat_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,13 +21,13 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: chat_msg.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $
+#   $Id: chat_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Contains class definitions for manipulating <chat/> messages
 #
 #
 
-__version__ = "$Id: chat_msg.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: chat_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpgCore import *
 from chat_version import CHAT_VERSION
@@ -48,8 +48,7 @@
         self.takexml(xml_text)
 
     def __del__(self):
-        if self.chat_dom:
-            self.chat_dom.unlink()
+        if self.chat_dom: self.chat_dom.unlink()
 
     def toxml(self):
         return tostring(self.chat_dom)
--- a/orpg/chat/chatwnd.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/chatwnd.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
@@ -37,7 +37,7 @@
 #   + Added simple_html_repair() to post() to fix malformed html in the chat window
 #
 
-__version__ = "$Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $"
+__version__ = "$Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
@@ -45,11 +45,10 @@
 ##
 import os, time, re, sys, traceback, webbrowser, commands, chat_msg, chat_util
 
-from orpg.orpg_version import VERSION
+from orpg.orpg_version import VERSION, DISTRO, DIS_VER, BUILD
 from orpg.orpg_windows import *
 from orpg.player_list import WG_LIST
 from orpg.dirpath import dir_struct
-#from orpg.tools.metamenus import MenuEx #Needed?
 from string import *
 
 import cStringIO # for reading inline imagedata as a stream
@@ -62,11 +61,11 @@
 from orpg.tools.orpg_settings import settings
 import orpg.tools.predTextCtrl
 from orpg.tools.orpg_log import logger, debug
+from orpg.tools.InterParse import Parse
 from orpg.orpgCore import component
 from xml.etree.ElementTree import tostring
 
-from orpg.networking.mplay_client import MPLAY_CONNECTED  # needed to only send typing/not_typing messages while connected
-
+from orpg.networking.mplay_client import MPLAY_CONNECTED  
 NEWCHAT = False
 try:
     import wx.webview
@@ -83,10 +82,10 @@
         self.accum = ""
         self.special_tags = ['hr', 'br', 'img']
     
-    def handle_data(self, data):  # quote cdata literally
+    def handle_data(self, data):  
         self.accum += data
     
-    def handle_entityref(self, name): # entities must be preserved exactly
+    def handle_entityref(self, name): 
         self.accum += "&" + name + ";"
     
     def handle_starttag(self, tag, attrs):
@@ -95,11 +94,10 @@
             for attrib in attrs: self.accum += ' ' + attrib[0] + '="' + attrib[1] + '"'
             self.accum += '>'
     
-    def handle_charref(self, name):  # charrefs too
+    def handle_charref(self, name):
         self.accum += "&#" + name + ";"
 htmlstripper = HTMLStripper()
 
-# utility function;  see Post().
 
 def strip_html(string):
     "Return string tripped of html tags."
@@ -114,7 +112,6 @@
     filename = settings.get_setting('GameLogPrefix')
     if filename > '' and filename[0] != commands.ANTI_LOG_CHAR:
         filename = filename + time.strftime( '-%Y-%m-%d.html', time.localtime( time.time() ) )
-        #filename = time.strftime( filename, time.localtime( time.time() ) )
         timestamp = time.ctime(time.time())
         header = '[%s] : ' % ( timestamp );
         if settings.get_setting('TimeStampGameLog') != '1': header = ''
@@ -122,8 +119,9 @@
             f = open( dir_struct["user"] + filename, 'a' )
             f.write( '<div class="'+c+'">%s%s</div>\n' % ( header, text ) )
             f.close()
-        except:
+        except Exception, e:
             print "could not open " + dir_struct["user"] + filename + ", ignoring..."
+            print 'Error given', e
             pass
 
 # This class displayes the chat information in html?
@@ -136,12 +134,7 @@
 #
 class chat_html_window(wx.html.HtmlWindow):
     """ a wxHTMLwindow that will load links  """
-    # initialization subroutine
-    #
-    # !self : instance of self
-    # !parent :
-    # !id :
-    
+
     def __init__(self, parent, id):
         wx.html.HtmlWindow.__init__(self, parent, id, 
                                     style=wx.SUNKEN_BORDER|wx.html.HW_SCROLLBAR_AUTO|wx.NO_FULL_REPAINT_ON_RESIZE)
@@ -150,18 +143,14 @@
         self.Bind(wx.EVT_LEFT_UP, self.LeftUp)
         self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
         if "gtk2" in wx.PlatformInfo: self.SetStandardFonts()
-        # def __init__ - end
 
-    
     def onPopup(self, evt):
         self.PopupMenu(self.menu)
 
-    
     def LeftUp(self, event):
         event.Skip()
         wx.CallAfter(self.parent.set_chat_text_focus, None)
 
-    
     def build_menu(self):
         self.menu = wx.Menu()
         item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy")
@@ -174,13 +163,11 @@
         wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText()))
         wx.TheClipboard.Close()
 
-    
     def scroll_down(self):
         maxrange = self.GetScrollRange(wx.VERTICAL)
         pagesize = self.GetScrollPageSize(wx.VERTICAL)
         self.Scroll(-1, maxrange-pagesize)
 
-    
     def mouse_wheel(self, event):
         amt = event.GetWheelRotation()
         units = amt/(-(event.GetWheelDelta()))
@@ -197,19 +184,12 @@
     
     def GetPageSource(self):
         return self.GetParser().GetSource()
-
-    # This subroutine fires up the webbrowser when a link is clicked.
-    #
-    # !self : instance of self
-    # !linkinfo : instance of a class that contains the link information
     
     def OnLinkClicked(self, linkinfo):
         href = linkinfo.GetHref()
         wb = webbrowser.get()
         wb.open(href)
-    # def OnLinkClicked - end
 
-    
     def CalculateAllFonts(self, defaultsize):
         return [int(defaultsize * 0.4),
                 int(defaultsize * 0.7),
@@ -219,7 +199,6 @@
                 int(defaultsize * 2),
                 int(defaultsize * 2.5)]
 
-    
     def SetDefaultFontAndSize(self, fontname, fontsize):
         """Set 'fontname' to the default chat font.
            Returns current font settings in a (fontname, fontsize) tuple."""
@@ -239,7 +218,6 @@
             self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
             self.Bind(wx.webview.EVT_WEBVIEW_BEFORE_LOAD, self.OnLinkClicked)
 
-        #Wrapers so I dont have to add special Code
         def SetPage(self, htmlstring):
             self.SetPageSource(htmlstring)
 
@@ -366,7 +344,6 @@
 
     def get_tab_index(self, chatpanel):
         "Return the index of a chatpanel in the wxNotebook."
-
         for i in xrange(self.GetPageCount()):
             if (self.GetPage(i) == chatpanel):
                 return i
@@ -450,7 +427,6 @@
         selected_idx = event.GetSelection()
         self.SetPageImage(selected_idx, 1)
         page = self.GetPage(selected_idx)
-        #wx.CallAfter(page.set_chat_text_focus, 0)
         event.Skip()
 
 """
@@ -505,10 +481,6 @@
         # who receives outbound messages, either "all" or "playerid" string
         self.sendtarget = sendtarget
         self.type = tab_type
-        #self.sound_player = component.get('sound') #Removing!
-        # create die roller manager
-        #self.DiceManager = component.get('DiceManager') #Removing!
-        # create rpghex tool
         self.r_h = orpg.tools.rgbhex.RGBHex()
         self.h = 0
         self.set_colors()
@@ -530,13 +502,13 @@
                     wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10', 
                     wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'}
         #Alias Lib stuff
-        self.defaultAliasName = 'Use Real Name'
+        self.defaultAliasName = 'Real Name'
         self.defaultFilterName = 'No Filter'
         self.advancedFilter = False
         self.lastSend = 0         #  this is used to help implement the player typing indicator
         self.lastPress = 0        #  this is used to help implement the player typing indicator
         self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) #require to keep text at bottom of chat when text entry expands --SD
+        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) 
         self.build_ctrls()
         StartupFont = self.settings.get_setting("defaultfont")
         StartupFontSize = self.settings.get_setting("defaultfontsize")
@@ -778,7 +750,6 @@
         self.build_menu()
         entries = []
         entries.append((wx.ACCEL_CTRL, ord('H'), self.setChatFocusMenu.GetId()))
-        #entries.append((wx.ACCEL_CTRL, wx.WXK_TAB, SWAP_TABS))
         return entries
 
     
@@ -788,18 +759,15 @@
     def back_tabs(self, evt):
         self.parent.AdvanceSelection(False)
 
-    # This subroutine builds the controls for the chat frame
-    #
-    # !self : instance of self
-    
     def build_ctrls(self):
         self.chatwnd = chat_html_window(self,-1)
         self.set_colors()
         wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header())
+        welcome = "<b>Welcome to <a href='http://www.knowledgearcana.com/traipse-openrpg/'>"
+        welcome += DISTRO +'</a> '+ DIS_VER +' {'+BUILD+'},'
+        welcome += ' built on OpenRPG '+ VERSION +'</b>'
         if (self.sendtarget == "all"):
-            wx.CallAfter(self.Post, self.colorize(self.syscolor, 
-                "<b>Welcome to <a href='http://www.openrpg.com'>OpenRPG</a> version " + self.version + "...  </b>"))
-            #self.chat_cmds.on_help()
+            wx.CallAfter(self.Post, self.colorize(self.syscolor, welcome))
         self.chattxt = orpg.tools.predTextCtrl.predTextCtrl(self, -1, "", 
                         style=wx.TE_PROCESS_ENTER |wx.TE_PROCESS_TAB|wx.TE_LINEWRAP, 
                         keyHook = self.myKeyHook, validator=None )
@@ -838,7 +806,6 @@
         self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar)
         self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down)
         self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy)
-    # def build_ctrls - end
 
     def build_bar(self):
         self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -855,14 +822,12 @@
             self.build_formating()
             self.build_colorbutton()
 
-    
     def build_scroll(self):
         self.scroll_lock = wx.Button( self, wx.ID_ANY, "Scroll ON",size= wx.Size(80,25))
 
-    
     def build_alias(self):
         self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName])
+        self.aliasList = wx.Choice(self, wx.ID_ANY, size=(120, 25), choices=[self.defaultAliasName])
         self.aliasButton = createMaskedButton( self, dir_struct["icon"] + 'player.gif', 
                                             'Refresh list of aliases from Game Tree', 
                                             wx.ID_ANY, '#bdbdbd' )
@@ -949,8 +914,6 @@
         else: self.toolbar_sizer.Show(self.formatSizer, True)
         self.toolbar_sizer.Layout()
 
-    # Heroman - Ideally, we would use static labels...
-    
     def build_colorbutton(self):
         self.color_button = createMaskedButton(self, dir_struct["icon"]+'textcolor.gif', 
                                                     'Text Color', wx.ID_ANY, '#bdbdbd', 
@@ -983,13 +946,6 @@
         else: logger.general("Error, self.chatwnd.GetInternalRepresentation() return None")
         evt.Skip()
 
-    #  This subroutine is registered with predTextCtrl to be run for every OnChar event
-    #  It checks if we need to send a typing message
-
-    #
-    #  self:  duh
-    #  event:  raw KeyEvent from OnChar()
-    
     def myKeyHook(self, event):
         if self.session.get_status() == MPLAY_CONNECTED:   #  only do if we're connected
             thisPress = time.time()                #  thisPress is local temp variable
@@ -1005,11 +961,6 @@
             logger.debug("Exit chat_panel->myKeyHook(self, event) return 0")
             return 0
 
-    #  This subroutine gets called once a second by the typing Timer
-    #  It checks if we need to send a not_typing message
-    #
-    #  self:  duh
-    
     def typingTimerFunc(self, event):
         #following added by mDuo13
         ##############refresh_counter()##############
@@ -1027,12 +978,7 @@
                                                    #  If we're not already typing, then self.lastSend will be 0
 
                 self.sendTyping(0)                 #  send a typing event here (0 for False)
-    #  This subroutine actually takes care of sending the messages for typing/not_typing events
-    #
-    #  self:  duh
-    #  typing:  boolean
 
-    
     def sendTyping(self, typing):
         if typing:
             self.lastSend = time.time()  #  remember our send time for use in myKeyHook()
@@ -1047,11 +993,6 @@
             if status_text == "" or status_text == None: status_text = "Idle"
             self.session.set_text_status(status_text)
 
-    # This subroutine sets the colors of the chat based on the settings in the
-    # self instance.
-    #
-    # !self : instance of self
-    
     def set_colors(self):
         # chat window backround color
         self.bgcolor = self.settings.get_setting('bgcolor')
@@ -1067,18 +1008,11 @@
         self.emotecolor = self.settings.get_setting('emotecolor')
         # color of whispers
         self.whispercolor = self.settings.get_setting('whispercolor')
-    # def set_colors - end
-
-    # This subroutine will insert text into the chat window
-    #
-    # !self : instance of self
-    # !txt : text to be inserted into the chat window
     
     def set_chat_text(self, txt):
         self.chattxt.SetValue(txt)
         self.chattxt.SetFocus()
         self.chattxt.SetInsertionPointEnd()
-    # def set_chat_text - end
 
     
     def get_chat_text(self):
@@ -1088,28 +1022,17 @@
     
     def set_chat_text_focus(self, event):
         wx.CallAfter(self.chattxt.SetFocus)
-    # def set_chat_text_focus - end
-
-    # This subrtouine grabs the user input and make the special keys and
-    # modifiers work.
-    #
-    # !self : instance of self
-    # !event :
-    #
-    # Note:  self.chattxt now handles it's own Key events.  It does, however still
-    #        call it's parent's (self) OnChar to handle "default" behavior.
 
     def submit_chat_text(self, s):
         self.histidx = -1
         self.temptext = ""
         self.history = [s] + self.history 
-        #if not len(macroText): self.chattxt.SetValue("")
 
         # play sound
         sound_file = self.settings.get_setting("SendSound")
         if sound_file != '': component.get('sound').play(sound_file)
         if s[0] != "/": ## it's not a slash command
-            s = self.ParsePost( s, True, True )
+            s = Parse.Post(s, self, True, True)
         else: self.chat_cmds.docmd(s) # emote is in chatutils.py
 
     def on_chat_key_down(self, event):
@@ -1144,17 +1067,12 @@
         elif event.GetKeyCode() == wx.WXK_UP:
             logger.debug("event.GetKeyCode() == wx.WXK_UP")
             if self.histidx < len(self.history)-1:
-                #text that's not in history but also hasn't been sent to chat gets stored in self.temptext
-                #this way if someone presses the up key, they don't lose their current message permanently
-                #(unless they also press enter at the time)
                 if self.histidx is -1: self.temptext = self.chattxt.GetValue()
                 self.histidx += 1
                 self.chattxt.SetValue(self.history[self.histidx])
                 self.chattxt.SetInsertionPointEnd()
             else:
-                self.histidx = len(self.history) -1#in case it got too high somehow, this should fix it
-                #self.InfoPost("**Going up? I don't think so.**")
-            #print self.histidx, "in",self.history
+                self.histidx = len(self.history) -1
 
         ## DOWN KEY
         elif event.GetKeyCode() == wx.WXK_DOWN:
@@ -1166,9 +1084,7 @@
                     self.chattxt.SetValue(self.temptext)
                 else: self.chattxt.SetValue(self.history[self.histidx])
                 self.chattxt.SetInsertionPointEnd()
-            else: self.histidx = -1 #just in case it somehow got below -1, this should fix it
-                #self.InfoPost("**Going down? I don't think so.**")
-            #print self.histidx, "in",self.history
+            else: self.histidx = -1 
 
         ## TAB KEY
         elif  event.GetKeyCode() == wx.WXK_TAB:
@@ -1242,8 +1158,6 @@
         ## NOTHING
         else: event.Skip()
         logger.debug("Exit chat_panel->OnChar(self, event)")
-    # def OnChar - end
-
     
     def onDieRoll(self, evt):
         """Roll the dice based on the button pressed and the die modifiers entered, if any."""
@@ -1257,15 +1171,9 @@
         if len(dieMod) and dieMod[0] not in "*/-+": dieMod = "+" + dieMod
         dieText += dieMod
         dieText = "[" + dieText + "]"
-        self.ParsePost(dieText, 1, 1)
+        Parse.Post(dieText, self, 1, 1)
         self.chattxt.SetFocus()
 
-    # This subroutine saves a chat buffer as html to a file chosen via a
-    # FileDialog.
-    #
-    # !self : instance of self
-    # !evt :
-    
     def on_chat_save(self, evt):
         f = wx.FileDialog(self,"Save Chat Buffer",".","","HTM* (*.htm*)|*.htm*|HTML (*.html)|*.html|HTM (*.htm)|*.htm",wx.SAVE)
         if f.ShowModal() == wx.ID_OK:
@@ -1274,9 +1182,7 @@
             file.close()
         f.Destroy()
         os.chdir(dir_struct["home"])
-    # def on_chat_save - end
 
-    
     def ResetPage(self):
         self.set_colors()
         buffertext = self.chatwnd.Header() + "\n"
@@ -1286,9 +1192,6 @@
                                                                             "<br />\n").replace("\n\n", '')
         return buffertext
 
-    # This subroutine sets the color of selected text, or base text color if
-    # nothing is selected
-    
     def on_text_color(self, event):
         hexcolor = self.r_h.do_hex_color_dlg(self)
         if hexcolor != None:
@@ -1305,25 +1208,11 @@
                 self.settings.set_setting('mytextcolor',hexcolor)
                 self.set_colors()
                 self.Post()
-    # def on_text_color - end
 
-    # This subroutine take a color and a text string and formats it into html.
-    #
-    # !self : instance of self
-    # !color : color for the text to be set
-    # !text : text string to be included in the html.
-    
     def colorize(self, color, text):
         """Puts font tags of 'color' around 'text' value, and returns the string"""
         return "<font color='" + color + "'>" + text + "</font>"
-    # def colorize - end
 
-    # This subroutine takes and event and inserts text with the basic format
-    # tags included.
-    #
-    # !self : instance of self
-    # !event :
-    
     def on_text_format(self, event):
         id = event.GetId()
         txt = self.chattxt.GetValue()
@@ -1338,9 +1227,7 @@
         self.chattxt.SetValue(txt)
         self.chattxt.SetInsertionPointEnd()
         self.chattxt.SetFocus()
-    # def on_text_format - end
 
-    
     def lock_scroll(self, event):
         if self.lockscroll:
             self.lockscroll = False
@@ -1353,28 +1240,16 @@
             self.lockscroll = True
             self.scroll_lock.SetLabel("Scroll OFF")
 
-    # This subroutine will popup a text window with the chatbuffer contents
-    #
-    # !self : instance of self
-    # !event :
-    
     def pop_textpop(self, event):
         """searchable popup text view of chatbuffer"""
         h_buffertext = self.ResetPage()
         h_dlg = orpgScrolledMessageFrameEditor(self, h_buffertext, "Text View of Chat Window", None, (500,300))
         h_dlg.Show(True)
 
-    # This subroutine will change the dimension of the window
-    #
-    # !self : instance of self
-    # !event :
-    
     def OnSize(self, event=None):
         event.Skip()
         wx.CallAfter(self.scroll_down)
-    # def OnSize - end
 
-    
     def scroll_down(self):
         self.Freeze()
         self.chatwnd.scroll_down()
@@ -1386,17 +1261,14 @@
         self.set_colors()
         self.chatwnd.SetPage(self.chatwnd.Header())
 
-    
     def system_message(self, text):
         self.send_chat_message(text,chat_msg.SYSTEM_MESSAGE)
         self.SystemPost(text)
 
-    
     def info_message(self, text):
         self.send_chat_message(text,chat_msg.INFO_MESSAGE)
         self.InfoPost(text)
 
-    
     def get_gms(self):
         the_gms = []
         for playerid in self.session.players:
@@ -1404,7 +1276,6 @@
                 if self.session.players[playerid][7]=="GM" and self.session.group_id != '0': the_gms += [playerid]
         return the_gms
 
-    
     def GetName(self):
         self.AliasLib = component.get('alias')
         player = self.session.get_my_info()
@@ -1415,7 +1286,6 @@
                 return [self.chat_display_name([self.AliasLib.alias[0], player[1], player[2]]), self.AliasLib.alias[1]]
         return [self.chat_display_name(player), "Default"]
 
-    
     def GetFilteredText(self, text):
         advregex = re.compile('\"(.*?)\"', re.I)
         self.AliasLib = component.get('alias')
@@ -1430,11 +1300,9 @@
                         text = text.replace(match, newmatch)
         return text
 
-    
     def emote_message(self, text):
-        text = self.NormalizeParse(text)
+        text = Parse.Normalize(text, self)
         text = self.colorize(self.emotecolor, text)
-
         if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE)
         elif self.type == MAIN_TAB and self.sendtarget == "gm":
             msg_type = chat_msg.WHISPER_EMOTE_MESSAGE
@@ -1449,13 +1317,10 @@
         text = "** " + name + " " + text + " **"
         self.EmotePost(text)
 
-    
     def whisper_to_players(self, text, player_ids):
         tabbed_whispers_p = self.settings.get_setting("tabbedwhispers")
-        # Heroman - apply any filtering selected
-        text = self.NormalizeParse(text)
+        text = Parse.Normalize(text, self)
         player_names = ""
-        # post to our chat before we colorize
         for m in player_ids:
             id = m.strip()
             if self.session.is_valid_id(id):
@@ -1469,7 +1334,6 @@
         comma.join(player_ids)
         if (self.sendtarget == "all"):
             self.InfoPost("<i>whispering to "+ player_names + " " + text + "</i> ")
-        # colorize and loop, sending whisper messages to all valid clients
         text = self.colorize(self.mytextcolor, text)
         for id in player_ids:
             id = id.strip()
@@ -1501,18 +1365,13 @@
         if send: self.session.send(msg.toxml(),player_id)
         del msg
 
-    #### incoming chat message handler #####
-    
     def post_incoming_msg(self, msg, player):
-
-        # pull data
         type = msg.get_type()
         text = msg.get_text()
         alias = msg.get_alias()
         # who sent us the message?
         if alias: display_name = self.chat_display_name([alias, player[1], player[2]])
-        elif player: display_name = self.chat_display_name(player)
-        else: display_name = "Server Administrator"
+        else: display_name = self.chat_display_name(player)
 
         ######### START plugin_incoming_msg() ###########
         for plugin_fname in self.activeplugins.keys():
@@ -1522,14 +1381,11 @@
                 if str(e) != "'module' object has no attribute 'receive_msg'":
                     logger.general(traceback.format_exc())
                     logger.general("EXCEPTION: " + str(e))
-        #end mDuo13 added code
-        #image stripping for players' names
         strip_img = self.settings.get_setting("Show_Images_In_Chat")
         if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name)
-        #end image stripping. --mDuo13, July 11th, 2005
-        # default sound
         recvSound = "RecvSound"
         # act on the type of messsage
+
         if (type == chat_msg.CHAT_MESSAGE):
             text = "<b>" + display_name + "</b>: " + text
             self.Post(text)
@@ -1624,17 +1480,15 @@
         sound_file = self.settings.get_setting(recvSound)
         if sound_file != '':
             component.get('sound').play(sound_file)
+
     #### Posting helpers #####
 
-    
     def InfoPost(self, s):
         self.Post(self.colorize(self.infocolor, s), c='info')
 
-    
     def SystemPost(self, s):
         self.Post(self.colorize(self.syscolor, s), c='system')
 
-    
     def EmotePost(self, s):
         self.Post(self.colorize(self.emotecolor, s), c='emote')
 
@@ -1675,15 +1529,9 @@
         if aliasInfo[1] != 'Default':
             self.settings.set_setting("mytextcolor", defaultcolor)
             self.set_colors()
-        #following line based on sourceforge patch #880403 from mDuo
-        # EDIT: Had to rework blank line check to handle malformed HTML throwing error.
-        #       this limits the effectiveness of this check -SD
         lineHasText = 1
         try: lineHasText = strip_html(s).replace("&nbsp;","").replace(" ","").strip()!=""
         except:
-            # HTML parser has errored out (most likely). Being as all we are doing is
-            # scanning for empty/blank lines anyway there is no harm in letting a
-            # troublesome message though. Worst case is a blank line to chat.
             lineHasText = 1
         if lineHasText:
             #following added by mDuo13
@@ -1731,12 +1579,6 @@
             else: self.InfoPost("Failed to send message, unknown send type for this tab")
         self.parsed=0
 
-    #
-    # TimeIndexString()
-    #
-    # time indexing for chat display only (don't log time indexing)
-    # added by Snowdog 4/04
-    
     def TimeIndexString(self):
         try:
             mtime = ""
@@ -1749,94 +1591,13 @@
             logger.general("EXCEPTION: " + str(e))
             return "[ERROR]"
 
-    ####  Post with parsing dice ####
-    
-    def ParsePost(self, s, send=False, myself=False):
-        s = self.NormalizeParse(s)
-        self.set_colors()
-        self.Post(s,send,myself)
-    
-    def NormalizeParse(self, s):
-        for plugin_fname in self.activeplugins.keys():
-            plugin = self.activeplugins[plugin_fname]
-            try: s = plugin.pre_parse(s)
-            except Exception, e:
-                if str(e) != "'module' object has no attribute 'post_msg'":
-                    logger.general(traceback.format_exc())
-                    logger.general("EXCEPTION: " + str(e))
-        if self.parsed == 0:
-            s = self.ParseNode(s)
-            s = self.ParseDice(s)
-            s = self.ParseFilter(s)
-            self.parsed = 1
-        return s
-    
-    def ParseFilter(self, s):
-        s = self.GetFilteredText(s)
-        return s
-    
-    def ParseNode(self, s):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        #[a-zA-Z0-9 _\-\.]
-        reg = re.compile("(!@(.*?)@!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            newstr = self.ParseNode(self.resolve_nodes(matches[i][1]))
-            s = s.replace(matches[i][0], newstr, 1)
-        return s
-    
-    def ParseDice(self, s):
-        """Parses player input for embedded dice rolls"""
-        reg = re.compile("\[([^]]*?)\]")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            newstr = self.PraseUnknowns(matches[i])
-            qmode = 0
-            newstr1 = newstr
-            if newstr[0].lower() == 'q':
-                newstr = newstr[1:]
-                qmode = 1
-            if newstr[0].lower() == '#':
-                newstr = newstr[1:]
-                qmode = 2
-            try: newstr = component.get('DiceManager').proccessRoll(newstr)
-            except: pass
-            if qmode == 1:
-                s = s.replace("[" + matches[i] + "]", 
-                            "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
-            elif qmode == 2:
-                s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
-            else: s = s.replace("[" + matches[i] + "]", 
-                            "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
-        return s
-    
-    def PraseUnknowns(self, s):
-	# Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY
-        newstr = "0"
-        reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            lb = "Replace '?' with: "
-            if len(matches[i][0]):
-                lb = matches[i][1] + "?: "
-            dlg = wx.TextEntryDialog(self, lb, "Missing Value?")
-            dlg.SetValue('')
-            if matches[i][0] != '':
-                dlg.SetTitle("Enter Value for " + matches[i][1])
-            if dlg.ShowModal() == wx.ID_OK: newstr = dlg.GetValue()
-            if newstr == '': newstr = '0'
-            s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1)
-            dlg.Destroy()
-        return s
-
     # This subroutine builds a chat display name.
     #
     def chat_display_name(self, player):
-        if self.settings.get_setting("ShowIDInChat") == "0":
-            display_name = player[0]
-        else:
-            display_name = "("+player[2]+") " + player[0]
+        if player == None:
+            player = ['<b><i><u>Server Administrator</u>-></i></b> ', '127.0.0.1', '0']
+        if self.settings.get_setting("ShowIDInChat") == "0": display_name = player[0]
+        else: display_name = "("+player[2]+") " + player[0]
         return display_name
 
     # This subroutine will get a hex color and return it, or return nothing
@@ -1854,8 +1615,8 @@
         else:
             dlg.Destroy()
             return None
+
     # def get_color - end
-
     def replace_quotes(self, s):
         in_tag = 0
         i = 0
@@ -1869,179 +1630,3 @@
             i += 1
         return rs
 
-    def resolve_loop(self, node, path, step, depth):
-        if step == depth:
-            return self.resolution(node)
-        else:
-            child_list = node.findall('nodehandler')
-            for child in child_list:
-                if step == depth: break
-                if child.get('name') == path[step]:
-                    node = child
-                    step += 1
-                    if node.get('class') in ('dnd35char_handler', 
-                                            "SWd20char_handler", 
-                                            "d20char_handler", 
-                                            "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth)
-                    elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth)
-                    else: self.resolve_loop(node, path, step, depth)
-
-    def resolve_grid(self, node, path, step, depth):
-        if step == depth:
-            self.data = 'Invalid Grid Reference!'
-            return
-        cell = tuple(path[step].strip('(').strip(')').split(','))
-        grid = node.find('grid')
-        rows = grid.findall('row')
-        col = rows[int(self.ParseDice(cell[0]))-1].findall('cell')
-        try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data'
-        except: self.data = 'Invalid Grid Reference!'
-        return
-
-    def resolution(self, node):
-        if self.passed == False:
-            self.passed = True
-            if node.get('class') == 'textctrl_handler': 
-                s = str(node.find('text').text)
-            else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
-        else:
-            s = ''
-        s = self.ParseMap(s, node)
-        s = self.ParseParent(s, node.get('map'))
-        self.data = s
-
-    def ParseMap(self, s, node):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!!(.*?)!!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            tree_map = node.get('map')
-            tree_map = tree_map + '::' + matches[i][1]
-            newstr = '!@'+ tree_map +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            s = self.ParseNode(s)
-            s = self.ParseParent(s, tree_map)
-        return s
-
-    def ParseParent(self, s, tree_map):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!#(.*?)#!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            ## Build the new tree_map
-            new_map = tree_map.split('::')
-            del new_map[len(new_map)-1]
-            parent_map = matches[i][1].split('::')
-            ## Find an index or use 1 for ease of use.
-            try: index = new_map.index(parent_map[0])
-            except: index = 1
-            ## Just replace the old tree_map from the index.
-            new_map[index:len(new_map)] = parent_map
-            newstr = '::'.join(new_map)
-            newstr = '!@'+ newstr +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            #s = self.ParseMap(s, node) ## Needs to be added
-            s = self.ParseNode(s)
-        return s
-
-    def resolve_nodes(self, s):
-        self.passed = False
-        self.data = 'Invalid Reference!'
-        value = ""
-        path = s.split('::')
-        depth = len(path)
-        self.gametree = component.get('tree')
-        try: node = self.gametree.tree_map[path[0]]['node']
-        except Exception, e: return self.data
-        if node.get('class') in ('dnd35char_handler', 
-                                "SWd20char_handler", 
-                                "d20char_handler", 
-                                "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
-        elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
-        else: self.resolve_loop(node, path, 1, depth)
-        return self.data
-
-    def resolve_cust_loop(self, node, path, step, depth):
-        node_class = node.get('class')
-        ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
-        if step == depth: self.resolution(node)
-        ##Build Abilities dictionary##
-        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities')
-        else: ab = node.find('abilities')
-        ab_list = ab.findall('stat'); pc_stats = {}
-
-        for ability in ab_list:
-            pc_stats[ability.get('name')] = ( 
-                    str(ability.get('base')), 
-                    str((int(ability.get('base'))-10)/2) )
-            pc_stats[ability.get('abbr')] = ( 
-                    str(ability.get('base')), 
-                    str((int(ability.get('base'))-10)/2) )
-
-        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
-        else: ab = node.find('saves')
-        ab_list = ab.findall('save')
-        for save in ab_list:
-            pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
-            if save.get('name') == 'Fortitude': abbr = 'Fort'
-            if save.get('name') == 'Reflex': abbr = 'Ref'
-            if save.get('name') == 'Will': abbr = 'Will'
-            pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
-
-        if path[step].lower() == 'skill':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
-            node = node.find('skills')
-            child_list = node.findall('skill')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = child.get('rank')
-                    elif path[step+2].lower() == 'check':
-                        self.data = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']'
-            return
-
-        if path[step].lower() == 'feat':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
-            node = node.find('feats')
-            child_list = node.findall('feat')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
-            return
-        if path[step].lower() == 'cast':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snp')
-            node = node.find('spells')
-            child_list = node.findall('spell')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
-            return
-        if path[step].lower() == 'attack':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat')
-            if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm':
-                bonus_text = '(Melee)'
-                bonus = node.find('attacks')
-                bonus = bonus.find('melee')
-                bonus = bonus.attrib; d = int(pc_stats['Str'][1])
-            elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r':
-                bonus_text = '(Ranged)'
-                bonus = node.find('attacks')
-                bonus = bonus.find('ranged')
-                bonus = bonus.attrib; d = int(pc_stats['Dex'][1])
-            for b in bonus:
-                d += int(bonus[b])
-            bonus = str(d)
-            if path[step+2] == None: self.data = bonus
-            else:
-                weapons = node.find('attacks')
-                weapons = weapons.findall('weapon')
-                for child in weapons:
-                    if path[step+2].lower() == child.get('name').lower():
-                        self.data = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']'
-            return
-        elif pc_stats.has_key(path[step].title()):
-            if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
-            elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1]
-            elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
-            return
--- a/orpg/chat/commands.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/commands.py	Sat Jun 12 03:50:37 2010 -0500
@@ -7,7 +7,6 @@
 #   on_whisper(self,text)
 #
 
-
 import string, time
 import orpg.orpg_version
 import orpg.orpg_windows
@@ -26,63 +25,41 @@
 try:
     import cmd_ext
     print "Importing Developer Extended Command Set"
-except:
-    pass
+except: pass
 ##----------------------------------------------------------------
 
 ANTI_LOG_CHAR = '!'
 
 class chat_commands:
 
-    # Initialization subroutine.
-    #
-    # !self : instance of self
-    # !chat : instance of the chat window to write to
-    
     def __init__(self,chat):
         self.post = chat.Post
         self.colorize = chat.colorize
         self.session = chat.session
-        #self.send = chat.session.send
         self.settings = chat.settings
         self.chat = chat
         self.cmdlist = {}
         self.shortcmdlist = {}
         self.defaultcmds()
         self.defaultcmdalias()
-        # def __init__ - end
         self.previous_whisper = []
 
-
-        # This subroutine will take a text string and attempt to match to a series
-        # of implemented emotions.
-        #
-        # !self : instance of self
-        # !text : string of text matching an implemented emotion
-    
     def addcommand(self, cmd, function, helpmsg):
         if not self.cmdlist.has_key(cmd) and not self.shortcmdlist.has_key(cmd):
             self.cmdlist[cmd] = {}
             self.cmdlist[cmd]['function'] = function
             self.cmdlist[cmd]['help'] = helpmsg
-            #print 'Command Added: ' + cmd
 
-    
     def addshortcmd(self, shortcmd, longcmd):
         if not self.shortcmdlist.has_key(shortcmd) and not self.cmdlist.has_key(shortcmd):
             self.shortcmdlist[shortcmd] = longcmd
 
-    
     def removecmd(self, cmd):
         if self.cmdlist.has_key(cmd):
             del self.cmdlist[cmd]
         elif self.shortcmdlist.has_key(cmd):
             del self.shortcmdlist[cmd]
 
-        #print 'Command Removed: ' + cmd
-
-
-    
     def defaultcmds(self):
         self.addcommand('/help', self.on_help, '- Displays this help message')
         self.addcommand('/version', self.on_version, ' - Displays current version of OpenRPG.')
@@ -112,7 +89,6 @@
         self.addcommand('/purge', self.on_purge, 'This will clear the entire chat window')
         self.addcommand('/advfilter', self.on_filter, 'This will toggle the Advanced Filter')
 
-    
     def defaultcmdalias(self):
         self.addshortcmd('/?', '/help')
         self.addshortcmd('/he', '/me')
@@ -123,18 +99,14 @@
         self.addshortcmd('/date', '/time')
         self.addshortcmd('/desc', '/description')
         self.addshortcmd('/d', '/description')
-
-        #This is just an example or a differant way the shorcmd can be used
         self.addshortcmd('/sleep', '/me falls asleep')
 
-    
     def docmd(self,text):
         cmdsearch = string.split(text,None,1)
         cmd = string.lower(cmdsearch[0])
         start = len(cmd)
         end = len(text)
         cmdargs = text[start+1:end]
-
         if self.cmdlist.has_key(cmd):
             self.cmdlist[cmd]['function'](cmdargs)
         elif self.shortcmdlist.has_key(cmd):
@@ -143,37 +115,26 @@
             msg = "Sorry I don't know what %s is!" % (cmd)
             self.chat.InfoPost(msg)
 
-    
     def on_filter(self, cmdargs):
-        #print self.chat.advancedFilter
         test = not self.chat.advancedFilter
-        #print test
-
         for tab in self.chat.parent.whisper_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         for tab in self.chat.parent.null_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         for tab in self.chat.parent.group_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         if self.chat.parent.GMChatPanel != None:
             self.chat.parent.GMChatPanel.advancedFilter = not self.chat.advancedFilter
-
         self.chat.advancedFilter = not self.chat.advancedFilter
-
         if self.chat.advancedFilter:
             self.chat.InfoPost("Advanced Filtering has been turned On")
         else:
             self.chat.InfoPost("Advanced Filtering has been turned Off")
 
-    
     def on_purge(self, cmdargs):
         self.chat.PurgeChat()
         self.chat.InfoPost('Chat Buffer has been Purged!')
 
-    
     def on_sound(self, cmdargs):
         if len(cmdargs) < 8:
             self.chat.InfoPost("You must provide a URL for the file name, it does not work for just local sound files")
@@ -186,9 +147,7 @@
         else:
             snd = cmdargs.replace('&', '&amp;')
             loop = ''
-
         type = 'remote'
-
         (name, ip, id, text_status, version, protocol_version, client_string, role) = self.session.get_my_info()
         group_id = self.session.group_id
         if (role != 'Lurker' and group_id != '0') or self.session.get_status() != 1:
@@ -207,11 +166,9 @@
         else:
             self.chat.InfoPost("Something dun fuckered up Frank!")
 
-    
     def on_version(self, cmdargs=""):
         self.chat.InfoPost("Version is OpenRPG " + self.chat.version)
 
-    
     def on_load(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         try:
@@ -222,14 +179,12 @@
             print e
             self.chat.InfoPost("ERROR Loading settings")
 
-    
     def on_font(self, cmdargs):
         try:
             fontsettings = self.chat.set_default_font(fontname=cmdargs, fontsize=None)
         except:
             self.chat.InfoPost("ERROR setting default font")
 
-    
     def on_fontsize(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         try:
@@ -238,7 +193,6 @@
             print e
             self.chat.InfoPost("ERROR setting default font size")
 
-    
     def on_close(self, cmdargs):
         try:
             chatpanel = self.chat
@@ -250,7 +204,6 @@
         except:
             self.chat.InfoPost("Error:  cannot close private chat tab.")
 
-    
     def on_time(self, cmdargs):
         local_time = time.localtime()
         gmt_time = time.gmtime()
@@ -258,30 +211,30 @@
         self.chat.InfoPost("<br />Local: " + time.strftime(format_string)+\
                            "<br />GMT: "+time.strftime(format_string,gmt_time))
 
-    
     def on_dieroller(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         rm = component.get('DiceManager')
+        cur_die = rm.getRoller()
+        if len(args) == 0: self.chat.InfoPost('You are using the <b>"' +cur_die+ '"</b> die roller.'); return
         try:
             rm.setRoller(args[0])
-            self.chat.SystemPost("You have changed your die roller to the <b>\"" + args[0] + "\"</b> roller.")
-            self.settings.set_setting('dieroller',args[0])
+            self.chat.SystemPost('You have changed your die roller to the <b>"' +rm.getRoller()+ '"</b> roller.')
+            self.settings.change('dieroller', rm.getRoller())
         except Exception, e:
-            print e
-            self.chat.InfoPost("Available die rollers: " + str(rm.listRollers()))
-            self.chat.InfoPost("You are using the <b>\"" + rm.getRoller() + "\"</b> die roller.")
+            rm.setRoller(cur_die)
+            self.settings.change('dieroller', str(cur_die))
+            if args[0] != '': self.chat.SystemPost(args[0]+ ' is an invalid roller.')
+            self.chat.InfoPost('Available die rollers: ' +str(rm.listRollers()) )
+            self.chat.InfoPost('You are using the <b>"' +cur_die+ '"</b> die roller.')
 
-    
     def on_ping(self, cmdargs):
         ct = time.clock()
         msg = "<ping player='"+self.session.id+"' time='"+str(ct)+"' />"
         self.session.outbox.put(msg)
 
-    
     def on_log(self,cmdargs):
         args = string.split(cmdargs,None,-1)
         logfile = self.settings.get_setting( 'GameLogPrefix' )
-
         if len( args ) == 0:
             self.postLoggingState()
         elif args[0] == "on" and logfile != '':
@@ -309,7 +262,6 @@
         else:
             self.chat.InfoPost("Unknown logging command, use 'on' or 'off'"  )
 
-    
     def postLoggingState( self ):
         logfile = self.settings.get_setting( 'GameLogPrefix' )
         try:
@@ -319,39 +271,23 @@
         suffix = time.strftime( '-%d-%m-%y.html', time.localtime( time.time() ) )
         self.chat.InfoPost('Log filename is "%s%s", system is %s logging.' % (logfile, suffix, comment) )
 
-        # This subroutine will set the players netork status.
-        #
-        #!self : instance of self
-
-    
     def on_name(self, cmdargs):
-        #only 20 chars no more! :)
         if cmdargs == "":
             self.chat.InfoPost("**Incorrect syntax for name.")
         else:
-            #txt = txt[:50]
             self.settings.set_setting('player', cmdargs)
             self.session.set_name(str(cmdargs))
 
-    # def on_status - end
-        # This subroutine will set the players netork status.
-        #
-        # !self : instance of self
-    
     def on_status(self, cmdargs):
         if cmdargs ==  "":
             self.chat.InfoPost("Incorrect synatx for status.")
         else:
-        #only 20 chars no more! :)
             txt = cmdargs[:20]
             self.session.set_text_status(str(txt))
-    # def on_status - end
 
-    
     def on_set(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         keys = self.settings.get_setting_keys()
-        #print keys
         if len(args) == 0:
             line = "<table border='2'>"
             for m in keys:
@@ -378,11 +314,6 @@
                         self.chat.set_colors()
                         self.chat.set_buffersize()
 
-        # This subroutine will display the correct usage of the different emotions.
-        #
-        #!self : instance of self
-
-    
     def on_help(self, cmdargs=""):
         cmds = self.cmdlist.keys()
         cmds.sort()
@@ -400,11 +331,6 @@
             msg += ' %s' % (self.cmdlist[cmd]['help'])
         self.chat.InfoPost(msg)
 
-        # This subroutine will either show the list of currently ignored users
-        # !self : instance of self
-        # !text : string that is comprised of a list of users to toggle the ignore flag
-
-    
     def on_ignore(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         (ignore_list, ignore_name) = self.session.get_ignore_list()
@@ -431,7 +357,6 @@
                     self.chat.InfoPost(m + " was ignored because it is an invalid player ID")
                     traceback.print_exc()
 
-    
     def on_role(self, cmdargs):
         if cmdargs == "":
             self.session.display_roles()
@@ -453,16 +378,7 @@
                     for m in player_ids:
                         self.session.set_role(m.strip(),role,role_pwd)
             except:  traceback.print_exc()
-#        return
 
-        # This subroutine implements the whisper functionality that enables a user
-        # to whisper to another user.
-        #
-        # !self : instance of self
-        # !text : string that is comprised of a list of users and the message to
-        #whisper.
-
-    
     def on_whisper(self, cmdargs):
         delim = cmdargs.find("=")
 
@@ -476,10 +392,6 @@
         mesg = string.strip(cmdargs[delim+1:])
         self.chat.whisper_to_players(mesg,player_ids)
 
-#---------------------------------------------------------
-# [START] Digitalxero Multi Whisper Group 1/1/05
-#---------------------------------------------------------
-    
     def on_groupwhisper(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         delim = cmdargs.find("=")
@@ -533,11 +445,6 @@
                 else: idList = str(n) + ", " + idList
             self.on_whisper(idList + "=" + self.settings.get_setting("gwtext") + msg)
 
-#---------------------------------------------------------
-# [END] Digitalxero Multi Whisper Group 1/1/05
-#---------------------------------------------------------
-
-    
     def on_gmwhisper(self, cmdargs):
         if cmdargs == "":
             self.chat.InfoPost("**Incorrect syntax for GM Whisper.")
@@ -551,7 +458,6 @@
                 self.on_whisper(gmstring + "=" + cmdargs)
             else: self.chat.InfoPost("**No GMs to Whisper to.")
 
-    
     def on_moderate(self, cmdargs):
         if cmdargs != "":
             pos = cmdargs.find("=")
@@ -584,11 +490,9 @@
             self.session.outbox.put(msg)
         self.session.update()
 
-    
     def on_update(self, cmdargs):
         self.chat.InfoPost("This command is no longer valid")
 
-    
     def on_description(self, cmdargs):
         if len(cmdargs) <= 0:
             self.chat.InfoPost("**No description text to display." + str(delim))
@@ -599,13 +503,10 @@
         self.chat.Post(mesg)
         self.chat.send_chat_message(mesg)
 
-    
     def invoke_tab(self, cmdargs):
-        ######START mDuo13's Tab Initiator########
         try:
             int(cmdargs)
             playerid = cmdargs.strip()
-            # Check to see if parent notebook already has a private tab for player
             for panel in self.chat.parent.whisper_tabs:
                 if (panel.sendtarget == playerid):
                     self.chat.Post("Cannot invoke tab: Tab already exists.")
@@ -622,30 +523,22 @@
             nidx = self.chat.parent.get_tab_index(displaypanel)
             self.chat.parent.newMsg(nidx)
             return
-        #######END mDuo13's Tab Initiator#########
 
-
-    
     def on_remote_admin(self, cmdargs):
         args = string.split(cmdargs,None,-1)
-        #handles remote administration commands
         try:
             pass_state = 0
             pwd = self.session.orpgFrame_callback.password_manager.GetSilentPassword("server")
             if  pwd != None:
                 pass_state = 1
             else: pwd = "<i>[NONE]</i>"
-
             if len( args ) == 0:
-                #raw command return state info
                 msg = "<br /><b>Remote Administrator Config:</b>"
                 if pass_state != 1 : msg += " Password not set. Remote admin functions disabled<br />"
                 else: msg += " Enabled. Using password '"+pwd+"'<br />"
                 self.chat.SystemPost(msg)
                 return
-
             if pass_state != 1 and args[0] != "set":
-                #no commands under this point will execute unless an admin password has been previously set
                 self.chat.SystemPost("Command ignored. No remote administrator password set!!")
                 return
             msgbase = "<admin id='"+self.session.id+"' group_id='"+self.session.group_id+"' pwd='"+pwd+"'"
@@ -690,14 +583,12 @@
                     self.session.outbox.put(msg)
 
             elif args[0] == "banip":
-                #Ban a player from the server
                 try: bname = str(args[2])
                 except: bname = 'Unknown'
                 msg = msgbase + ' cmd="banip" bip="' + str(args[1]) + '" bname="' + bname + '"/>'
                 self.session.outbox.put(msg)
 
             elif args[0] == "createroom":
-                #request creation of a (temporary) persistant room
                 if len(args) < 2:
                     self.chat.SystemPost( "You must supply a name and boot password at least. <br />/admin createroom &lt;name&gt; &lt;boot password&gt; [password]" )
                     return
@@ -709,7 +600,6 @@
                 self.session.outbox.put(msg)
 
             else: self.chat.InfoPost("Unknown administrator command"  )
-            #command_function = {'banip': self.admin.r_admin_banip, 'createroom': self.r_admin_createroom,}
         except:
             self.chat.InfoPost("An error has occured while processing a Remote Administrator command!")
             traceback.print_exc()
--- a/orpg/dieroller/base.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/base.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,18 +22,16 @@
 # Author: Andrew Bennett
 # Maintainer:
 # Version:
-#   $Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $
+#   $Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This class is used to make working with dice easier
 #
 
-__version__ = "$Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $"
-
+__version__ = "$Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp Exp $"
 
 import random
 import UserList
 import copy
-#import string
 
 class die_base(UserList.UserList):
     name = None
@@ -42,11 +40,9 @@
         if isinstance(source, (int, float, basestring)):
             s = []
             s.append(di(source))
-        else:
-            s = source
+        else: s = source
         UserList.UserList.__init__(self,s)
 
-
     def sum(self):
         s = 0
         for a in self.data:
@@ -58,28 +54,19 @@
             o = other
         elif hasattr(other,"sum"):
             o = other.sum()
-        else:
-            return None
-
+        else: return None
         result = []
         for die in self:
-            if die < o:
-                result.append(die)
+            if die < o: result.append(die)
         return self.__class__(result)
 
     def __rshift__(self,other):
-
-        if type(other) == type(3) or type(other) == type(3.0):
-            o = other
-        elif hasattr(other,"sum"):
-            o = other.sum()
-        else:
-            return None
-
+        if type(other) == type(3) or type(other) == type(3.0): o = other
+        elif hasattr(other,"sum"): o = other.sum()
+        else: return None
         result = []
         for die in self:
-            if die > o:
-                result.append(die)
+            if die > o: result.append(die)
         return self.__class__(result)
 
     def __rlshift__(self,other):
@@ -88,77 +75,58 @@
     def __rrshift__(self,other):
         return self.__lshift__(other)
 
-
     def __str__(self):
+        try: print "MY STRING", myStr
+        except: pass
         if len(self.data) > 0:
             myStr = "[" + str(self.data[0])
             for a in self.data[1:]:
                 myStr += ","
                 myStr += str(a)
             myStr += "] = (" + str(self.sum()) + ")"
-        else:
-            myStr = "[] = (0)"
+        else: myStr = "[] = (0)"
         return myStr
 
     def __lt__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() < other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() < other.sum())
-        else:
-            return UserList.UserList.__lt__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() < other.sum())
+        else: return UserList.UserList.__lt__(self,other)
 
     def __le__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() <= other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() <= other.sum())
-        else:
-            return UserList.UserList.__le__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() <= other.sum())
+        else: return UserList.UserList.__le__(self,other)
 
     def __eq__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() == other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() == other.sum())
-        else:
-            return UserList.UserList.__eq__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() == other.sum())
+        else: return UserList.UserList.__eq__(self,other)
 
     def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() != other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() != other.sum())
-        else:
-            return UserList.UserList.__ne__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() != other)
+        elif hasattr(other,"sum"): return (self.sum() != other.sum())
+        else: return UserList.UserList.__ne__(self,other)
 
     def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() > other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() > other.sum())
-        else:
-            return UserList.UserList.__gt__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() > other)
+        elif hasattr(other,"sum"): return  (self.sum() > other.sum())
+        else: return UserList.UserList.__gt__(self,other)
 
     def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() >= other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() >= other.sum())
-        else:
-            return UserList.UserList.__ge__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() >= other)
+        elif hasattr(other,"sum"): return  (self.sum() >= other.sum())
+        else: return UserList.UserList.__ge__(self,other)
 
     def __cmp__(self,other):
         #  this function included for backwards compatibility
         #  As of 2.1, lists implement the "rich comparison"
         #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0):
-            return cmp(self.sum(), other)
-        elif hasattr(other,"sum"):
-            return  cmp(self.sum(), other.sum())
-        else:
-            return UserList.UserList.__cmp__(self,other)
-
+        if type(other) == type(3) or type(other) == type(3.0): return cmp(self.sum(), other)
+        elif hasattr(other,"sum"): return  cmp(self.sum(), other.sum())
+        else: return UserList.UserList.__cmp__(self,other)
 
     def __rcmp__(self,other):
         return self.__cmp__(other)
@@ -166,16 +134,9 @@
     def __add__(self,other):
         mycopy = copy.deepcopy(self)
         if type(other) == type(3) or type(other) == type(3.0):
-            #if other < 0:
-            #    return self.__sub__(-other)
-            #other = [di(other,other)]
             other = [static_di(other)]
-            #return self.sum() + other
-
-        elif type(other) == type("test"):
-            return self
+        elif type(other) == type("test"): return self
         mycopy.extend(other)
-        #result = UserList.UserList.__add__(mycopy,other)
         return mycopy
 
     def __iadd__(self,other):
@@ -197,17 +158,13 @@
         mycopy = copy.deepcopy(self)
         if type(other) == type(3) or type(other) == type(3.0):
             neg_die = static_di(-other)
-            #neg_die.set_value(-other)
             other = [neg_die]
-            #return self.sum() - other
-        else:
-            other = -other
+        else: other = -other
         mycopy.extend(other)
         return mycopy
 
     def __rsub__(self,other):
         mycopy = -copy.deepcopy(self)
-        #print type(other)
         if type(other) == type(3) or type(other) == type(3.0):
             new_die = di(0)
             new_die.set_value(other)
@@ -219,89 +176,62 @@
         return self.__sub__(other)
 
     def __mul__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum() * other
-        elif hasattr(other,"sum"):
-            return other.sum() * self.sum()
-        else:
-            return UserList.UserList.__mul__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum() * other
+        elif hasattr(other,"sum"): return other.sum() * self.sum()
+        else: return UserList.UserList.__mul__(self,other)
 
     def __rmul__(self,other):
         return self.__mul__(other)
 
     def __div__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return float(self.sum()) / other
-        elif hasattr(other,"sum"):
-            return  float(self.sum()) / other.sum()
-        else:
-            return UserList.UserList.__div__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return float(self.sum()) / other
+        elif hasattr(other,"sum"): return  float(self.sum()) / other.sum()
+        else: return UserList.UserList.__div__(self,other)
 
     def __rdiv__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return other / float(self.sum())
-        elif hasattr(other,"sum"):
-            return  other.sum() / float(self.sum())
-        else:
-            return UserList.UserList.__rdiv__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return other / float(self.sum())
+        elif hasattr(other,"sum"): return  other.sum() / float(self.sum())
+        else: return UserList.UserList.__rdiv__(self,other)
 
     def __mod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum()%other
-        elif hasattr(other,"sum"):
-            return  self.sum() % other.sum()
-        else:
-            return UserList.UserList.__mod__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum()%other
+        elif hasattr(other,"sum"): return self.sum() % other.sum()
+        else: return UserList.UserList.__mod__(self,other)
 
     def __rmod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return other % self.sum()
-        elif hasattr(other,"sum"):
-            return  other.sum() % self.sum()
-        else:
-            return UserList.UserList.__rmod__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return other % self.sum()
+        elif hasattr(other,"sum"): return  other.sum() % self.sum()
+        else: return UserList.UserList.__rmod__(self,other)
 
     def __neg__(self):
-        for i in range(len(self.data)):
-            self.data[i] = -self.data[i]
+        for i in range(len(self.data)): self.data[i] = -self.data[i]
         return self
 
     def __pos__(self):
-        for i in range(len(self.data)):
-            self.data[i] = +self.data[i]
+        for i in range(len(self.data)): self.data[i] = +self.data[i]
         return self
 
     def __abs__(self):
-        for i in range(len(self.data)):
-            self.data[i] = abs(self.data[i])
+        for i in range(len(self.data)): self.data[i] = abs(self.data[i])
         return self
-        #return abs(self.sum())
 
     def __pow__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum() ** other
-        elif hasattr(other,"sum"):
-            return  self.sum() ** other.sum()
-        else:
-            return UserList.UserList.__pow__(self,other)
-
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum() ** other
+        elif hasattr(other,"sum"): return self.sum() ** other.sum()
+        else: return UserList.UserList.__pow__(self,other)
 
     def __rpow__(self,other):
         #  We're overloading exponentiation of ints to create "other" number of dice
-
         if other >= 1:
             result = self.__class__(self[0].sides)
-            for t in range(other-1):
-                result+=self.__class__(self[0].sides)
-        else:
-            result = None
-
+            for t in range(other-1): result+=self.__class__(self[0].sides)
+        else: result = None
         return result
 
 ### di class to handle actual dice
 
 class di:
-    def __init__(self,sides,min=1):
+    def __init__(self, sides, min=1):
         self.sides = sides
         self.history = None
         self.value = None
@@ -309,21 +239,17 @@
         self.roll(min)
 
     def __str__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
+        if len(self.history) > 1: return str(self.history)
+        else: return str(self.value)
 
     def __neg__(self):
         self.value = -self.value
-        for i in range(len(self.history)):
-            self.history[i] = -self.history[i]
+        for i in range(len(self.history)): self.history[i] = -self.history[i]
         return self
 
     def __pos__(self):
         self.value = +self.value
-        for i in range(len(self.history)):
-            self.history[i] = +self.history[i]
+        for i in range(len(self.history)): self.history[i] = +self.history[i]
         return self
 
     def __abs__(self):
@@ -333,90 +259,59 @@
         return self
 
     def __repr__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
+        if len(self.history) > 1: return str(self.history)
+        else: return str(self.value)
 
     def __int__(self):
         return self.value
 
-
     def __lt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value < other
-        elif hasattr(other,"value"):
-            return self.value < other.value
-        else:
-            return self < other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value < other
+        elif hasattr(other,"value"): return self.value < other.value
+        else: return self < other
 
     def __le__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value <= other
-        elif hasattr(other,"value"):
-            return self.value <= other.value
-        else:
-            return self <= other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value <= other
+        elif hasattr(other,"value"): return self.value <= other.value
+        else: return self <= other
 
     def __eq__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value == other
-        elif hasattr(other,"value"):
-            return self.value == other.value
-        else:
-            return self == other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value == other
+        elif hasattr(other,"value"): return self.value == other.value
+        else: return self == other
 
     def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value != other
-        elif hasattr(other,"value"):
-            return self.value != other.value
-        else:
-            return self != other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value != other
+        elif hasattr(other,"value"): return self.value != other.value
+        else: return self != other
 
     def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value > other
-        elif hasattr(other,"value"):
-            return self.value > other.value
-        else:
-            return self > other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value > other
+        elif hasattr(other,"value"): return self.value > other.value
+        else: return self > other
 
     def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value >= other
-        elif hasattr(other,"value"):
-            return self.value >= other.value
-        else:
-            return self >= other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value >= other
+        elif hasattr(other,"value"): return self.value >= other.value
+        else: return self >= other
 
     def __cmp__(self,other):
         #  this function included for backwards compatibility
         #  As of 2.1, lists implement the "rich comparison"
         #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0):
-            return cmp(self.value, other)
-        elif hasattr(other,"value"):
-            return cmp(self.value, other.value)
-        else:
-            return cmp(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return cmp(self.value, other)
+        elif hasattr(other,"value"): return cmp(self.value, other.value)
+        else: return cmp(self,other)
 
     def roll(self,min=1):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            self.value = random.randint(-1, 1)
-        else:
-            #self.value = random.randint(min, self.sides)
-            self.value = int(random.uniform(min, self.sides+1))
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f': self.value = random.randint(-1, 1)
+        else: self.value = int(random.uniform(min, self.sides+1))
         self.history = []
         self.history.append(self.value)
 
     def extraroll(self):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            result = random.randint(-1, 1)
-        else:
-            #result = random.randint(1, self.sides)
-            result = int(random.uniform(1,self.sides+1))
-
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f': result = random.randint(-1, 1)
+        else: result = int(random.uniform(1,self.sides+1))
         self.value += result
         self.history.append(result)
 
@@ -444,8 +339,7 @@
     _rollers = {}
     def __new__(cls):
         it = cls.__dict__.get("__it__")
-        if it is not None:
-            return it
+        if it is not None: return it
         cls.__it__ = it = object.__new__(cls)
         return it
 
--- a/orpg/dieroller/rollers/7sea.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/7sea.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,7 +23,7 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: WOD die roller
 #
@@ -31,7 +31,7 @@
 # for compatibility with Mage die rolls.
 # Threshhold addition by robert t childers
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
--- a/orpg/dieroller/rollers/__init__.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/__init__.py	Sat Jun 12 03:50:37 2010 -0500
@@ -5,4 +5,4 @@
 
 for roller in os.listdir(os.path.abspath(os.path.dirname(__file__))):
     if roller.endswith('.py') and not roller.startswith('__'):
-        __import__("%s.%s" % (rollers, roller.split('.')[0]))
\ No newline at end of file
+        __import__("%s.%s" % (rollers, roller.split('.')[0]))
--- a/orpg/dieroller/rollers/alternity.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/alternity.py	Sat Jun 12 03:50:37 2010 -0500
@@ -18,20 +18,49 @@
 #
 # Changelog:
 #
-# v.1 original release JEC
-#
-# Traipse Release: 
-# The changes made in the Traipe release are intended to create a more direct connection
-# between the source and the intrepretor. IF, ELIF statements have been replaced with dictionaries,
+# v.1 original release JEC
+#
+# Traipse Release: 
+# The changes made in the Traipe release are intended to create a more direct connection
+# between the source and the intrepretor. IF, ELIF statements have been replaced with dictionaries,
 # unused objects have been replace with re-usable objects, and the code has been condensed.
-
+#
+# SEG: JAN 24 2010 - v.1.4 O'Flux Release:
+# Edits & Additions: fixed a few minor bugs; Damage roll & Display Issues.
+# Added Secondary Damage Calculation and Display. Fix all errors.
+# Added proper results for Critcal Successes with failure ==> final Result Ordinary Success
+# Removed reduntent Method to make parent class true with all others working as child.
+# Made all special output same colour codes font size. Cleaned out old commented lines.
+# Tested for Traipse on Win 7
+#
+#  Skill Check Example:
+#  [1d20.sk(12,-2)]
+#  OUTPUT Example:
+#  => [6,-3] = (3) AMAZING Success
+#
+#  Pistol, Laser; 0 step -- Attack Example:
+#  [1d20.at(12,0,(1d4+1,"w"),(1d6+1,"w"),(1d4,"m"))]
+#  OUTPUT Example:
+#  => [1,0] = (1) CRITICAL SUCCESS AMAZING HIT
+#  ===> Damage [4] = (4) mortal ======> Secondary Damage (2) stun / (2) wound
+#
+#  Action Check Example:
+#  [1d20.ac(14,-1)]
+#  OUTPUT Example:
+#   => ACTION CHECK : [18,-3] = (15) Marginal failure
+#   -1 Step make up bonus next Action Check
+#
+#
 
 import re
-
+
 from std import std
 from time import time, clock
 from orpg.dieroller.base import di, die_base, die_rollers
 
+##from orpg.tools.orpg_log import debug
+
+
 __version__ = "$Id: alternity.py,v 0.1 2003/01/02 12:00:00 cchriss Exp $"
 
 # Alternity stands for "Alternity system" 20 sided die plus mods
@@ -49,6 +78,9 @@
     def at(self,score,mod,dmgo,dmgg,dmga):
       return at(self,score,mod,dmgo,dmgg,dmga)
 
+    def ac(self,score,mod):
+        return ac(self,score,mod)
+
 die_rollers.register(alternity)
 
 class sk(std):
@@ -59,25 +91,29 @@
         self.mod = mod
 
     def getMod(self,mod=0):
-        m=0
-        mods = { -4: -di(12), -3: -di(8), -2:  -di(6), -1: -di(4), 1: -di(4),
-                2: di(6), 3: di(8), 4: di(12), 5: di(20)}
-        if mod in mods.keys(): m = mods[mod].value
+        m=0
+        mods = { -4: -di(12), -3: -di(8), -2:  -di(6), -1: -di(4), 1: di(4),
+                2: di(6), 3: di(8), 4: di(12), 5: di(20)} # SEG fix 1: di(4) #
+        if mod in mods.keys(): m = mods[mod].value
         elif mod <= -5: m=-di(20).value
         elif mod == 6:  m=di(20).value + di(20).value
         elif mod >= 7:  m=di(20).value + di(20).value + di(20).value
         return m
 
     def getRolLStr(self):
-        myStr = "[" + str(self.data[0])
+        myStr = "[" + str(self.data[0])
         self.d20 = self.sum()
-        amod = self.getMod(self.mod)
-        self.dieRoll = self.d20 + amod
+        self.amod = self.getMod(self.mod)
+
+##        varN = "self.amod"
+##        debug(varN)
+##        debug(self.amod)  ## seg added debug output
+        
+        self.dieRoll = self.d20 + self.amod
         for a in self.data[1:]:
             myStr += ","
             myStr += str(a)
-        myStr += "," + str(amod) + "] = (" + str(self.dieRoll) + ")"
-        if ( self.d20 == 1 ): self.success = 'CS'
+        myStr += "," + str(self.amod) + "] = (" + str(self.dieRoll) + ")"
         if ( self.dieRoll <= self.score / 4 ): self.success = 'A'
         elif ( self.dieRoll <= self.score / 2 ): self.success = 'G'
         elif ( self.dieRoll <= self.score ): self.success = 'O'
@@ -86,51 +122,127 @@
         return myStr
 
     def __str__(self):
-        myStr = self.getRolLStr()
-        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
-                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
-                    'A': " <b>AMAZING Success</b>",
-                    'G': " <b>Good Success</b>",
-                    'O': " <b>Ordinary Success</b>",
-                    'F': " <b>failure</b>"}
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b>",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING Success</font></b>",
+                    'G': " <b><font size=2 color='#306EFF'>Good Success</font></b>",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary Success</font></b>",
+                    'F': " <b><font size=2 color='#41627E'>failure</font></b>"}
+
+        if ( self.d20 == 1 ):  myStr += successes['CS'] # SEG Dec 19 2009
         myStr += successes[self.success]
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += "          final result ==> "
+            myStr += successes['O'] # SEG JAN 23 2010
         return myStr
 
-class at(sk):
-    ## Traipse Usage: The source I received had the damage rolls like this 1d6s, with the damage type a
-    ## letter that could be sliced from the roll. However, the roll is parsed before the letter can be
-    ## sliced from it, and with the letter attached it created an error.
-    ##
-    ## The Traipse method puts the damage type and the damage roll into a Tuple, ie (1d6, 's').
-    ## When uing this method you must include single or double quoutes around the damage type or the
+class at(sk):
+    ## Traipse Usage: The source I received had the damage rolls like this 1d6s, with the damage type a
+    ## letter that could be sliced from the roll. However, the roll is parsed before the letter can be
+    ## sliced from it, and with the letter attached it created an error.
+    ##
+    ## The Traipse method puts the damage type and the damage roll into a Tuple, ie (1d6, 's').
+    ## When using this method you must include single or double quoutes around the damage type or the
     ## software will treat it as an object.
+
     def __init__(self,source=[],sc=10, mod=0, dmgo="(1d6, 's')",dmgg="(1d6, 'w')",dmga="(1d6, 'm')"):
         sk.__init__(self,source,sc,mod)
         self.dmgo = dmgo
         self.dmgg = dmgg
         self.dmga = dmga
 
-    def getdmg(self,dmgroll):
-        astr = "===> Damage "
+    def getdmg(self,dmgroll):
+        astr = "<b>===></b> Damage "
         droll = str(dmgroll[0])
+        xyz = droll.split('(')
+        secD = (int(xyz[1][:-1])/2)   ## SEG* Calculate Secondary Damage
+
+##        varN = "secD"
+##        debug(varN)
+##        debug(secD)  ## seg added debug output
+
         dtype = dmgroll[1]
         astr += droll
-        if dtype=="s": astr += " stun"
-        elif dtype=="w": astr += " wound"
-        elif dtype=="m":astr += " mortal"
+        if dtype=="s": astr += " <b><font size=2 color='#52D017'>stun</font></b><BR>"
+        elif dtype=="w":
+            astr += " <b><font size=2 color='#C11B17'>wound</font></b>"+" <b>======></b> Secondary Damage ("+str(secD) \
+                    +") <b><font size=2 color='#52D017'>stun</font></b><BR>"  # SEG* Display Secondary Damage
+        elif dtype=="m":
+            astr += " <b><font size=2 color='#FF0000'>mortal</font></b>"+" <b>======></b> Secondary Damage ("+str(secD) \
+                    +") <b><font size=2 color='#52D017'>stun</font></b>"+" <b>/</b> ("+str(secD)+") <b><font size=2 color='#C11B17'>wound</font></b><BR>"  # SEG* Display Secondary Damage
         return astr
 
     def __str__(self):
-        myStr = self.getRolLStr()
-        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
-                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
-                    'A': " <b><font color='#00aa00'>AMAZING HIT</font></b> ",
-                    'G': " <b>Good HIT</b> ",
-                    'O': " <b>Ordinary HIT</b> ",
-                    'F': " <b>miss</b>"}
-        myStr += successes[self.success]
-        if self.success == 'A': myStr += self.getdmg(self.dmga)
-        elif self.success == 'G': myStr += self.getdmg(self.dmgg)
-        elif self.success == 'O': myStr += self.getdmg(self.dmgo)
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+        
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b>",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING HIT</font></b><BR> ",
+                    'G': " <b><font size=2 color='#306EFF'>Good HIT</font></b><BR> ",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary HIT</font></b><BR> ",
+                    'F': " <b><font size=2 color='#41627E'>miss</font></b>"}
+        if ( self.d20 == 1 ):
+            myStr += successes['CS'] # SEG Dec 19 2009
+
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += successes['F'] # SEG JAN 23 2010
+            myStr += "          final result ==> "
+            self.success = 'O'
+
+        myStr += successes[self.success]
+        if self.success == 'A': myStr += self.getdmg(self.dmga)
+        elif self.success == 'G': myStr += self.getdmg(self.dmgg)
+        elif self.success == 'O': myStr += self.getdmg(self.dmgo)
         return myStr
-
+
+class ac(sk):
+    def __init__(self,source=[],sc=10,mod=0):
+        sk.__init__(self,source,sc,mod)
+
+    def __str__(self):
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+        
+        myStr = " <b><font color='#E42217'>ACTION CHECK : </font></b>"+myStr
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b><BR> -2 Step make up bonus next Action Check",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING Success</font></b>",
+                    'G': " <b><font size=2 color='#306EFF'>Good Success</font></b>",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary Success</font></b>",
+                    'F': " <b><font size=2 color='#41627E'>Marginal failure</font></b>"}
+        if ( self.d20 == 1 ):  myStr += successes['CS'] # SEG Dec 19 2009
+        myStr += successes[self.success]
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += " final result ==> "
+            myStr += successes['O'] # SEG JAN 23 2010
+        if ( self.d20 != 1 ) and (self.success == 'F') :
+            myStr += "<BR> -1 Step make up bonus next Action Check"
+            
+        return myStr
+
+
+
+
+
+
+
+
+
+
+
+
+        
+
--- a/orpg/dieroller/rollers/d20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/d20.py	Sat Jun 12 03:50:37 2010 -0500
@@ -14,10 +14,10 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $
+#   $Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: d20 die roller
-__version__ = "$Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 # d20 stands for "d20 system" not 20 sided die :)
 
@@ -30,8 +30,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
     def attack(self,AC,mod,critical):
         return d20attack(self,AC,mod,critical)
 
@@ -43,27 +41,23 @@
 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!"
-
+        if self.is_success(): myStr += " Success!"
+        else: myStr += " Failure!"
         return myStr
 
 
@@ -86,8 +80,7 @@
         self.critical_roll = 0
         if self.data[0] >= self.critical and self.is_hit():
             self.critical_roll = die_base(20) + self.mod
-            if self.critical_roll.sum() >= self.AC:
-                self.critical_result = 1
+            if self.critical_roll.sum() >= self.AC: self.critical_result = 1
 
     def is_critical(self):
         return self.critical_result
@@ -101,15 +94,9 @@
             myStr += ","
             myStr += str(a)
         myStr += "] = (" + str(self.sum()) + ")"
-
         myStr += " vs AC " + str(self.AC)
-
-        if self.is_critical():
-            myStr += " Critical"
+        if self.is_critical(): myStr += " Critical"
+        if self.is_hit(): myStr += " Hit!"
+        else: myStr += " Miss!"
+        return myStr
 
-        if self.is_hit():
-            myStr += " Hit!"
-        else:
-            myStr += " Miss!"
-
-        return myStr
--- a/orpg/dieroller/rollers/gurps.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/gurps.py	Sat Jun 12 03:50:37 2010 -0500
@@ -51,11 +51,9 @@
 
 from time import time, clock
 import random
-
 from std import std
 from orpg.dieroller.base import *
 
-
 __version__ = "$Id: gurps.py,v 1.5 2007/05/06 16:42:55 digitalxero Exp $"
 
 # gurps
@@ -66,9 +64,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
-# Original msk roll renamed to be easier to understand/remember
     def skill(self,skill,mod):
         return gurpsskill(self,skill,mod)
 
@@ -133,8 +128,6 @@
         else:
             if self.sum() == 18:
                 myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-#            elif self.sum() == 17 and (self.skill+self.mod < 16):
-#                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
             elif self.sum() == 17:
                 if (self.skill+self.mod) < 16:
                     myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
@@ -279,13 +272,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0]) 
+        for a in self.data[1:]:
+            myStr += "," 
+            myStr += str(a)
+        myStr += "] = " 
+        myStr += str(self.sum()) 
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
         elif self.sum() == 12:
@@ -310,13 +302,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0]) 
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = "
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
         elif self.sum() == 12 or self.sum() == 13:
@@ -347,13 +338,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]: 
+            myStr += ","
+            myStr += str(a) 
+        myStr += "] = "
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>You drop your weapon (& a <i>cheap</i> weapon breaks).</font> [B556]"
         elif self.sum() == 12 or self.sum() == 8:
@@ -386,13 +376,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += "," 
+            myStr += str(a)
+        myStr += "] = " 
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>You lose your balance;  you can do nothing else (not even free actions) until next turn, and all defenses -2 until next turn.</font> [B557]"
         elif self.sum() == 12:
--- a/orpg/dieroller/rollers/hackmaster.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/hackmaster.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,7 +22,7 @@
 # Author: Ric Soard
 # Maintainer:
 # Version:
-#   $Id: hackmaster.py,v 0.4 2003/08/12
+#   $Id: hackmaster.py,v Traipse 'Ornery-Orc' prof.ebral Exp
 #
 # Description: special die roller for HackMaster(C)(TM) RPG
 #               has penetration damage - .damage(bonus,honor)
@@ -32,7 +32,7 @@
 #
 #
 
-__version__ = "$Id: hackmaster.py,v 1.8 2006/11/15 12:11:22 digitalxero Exp $"
+__version__ = "$Id: hackmaster.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import random
 from std import std
@@ -120,7 +120,6 @@
         #this is a static die that adds honor, we want high rolls so it's +1
         self.append(static_di(self.hon))
 
-
     def check_crit(self):
         if self.data[0] == self.data[0].sides:
             self.crit = 1
@@ -170,7 +169,6 @@
         myStr += " Example [1d8.severity(1)] <br />"
         myStr += " .help() : <br />"
         myStr += " displays this message <br />"
-
         return myStr
 
 # the severity roll is for critical resolution. The die is rerolled and added
@@ -185,7 +183,6 @@
         self.CheckReroll()
         self.append(static_di(self.hon))
 
-
     def __str__(self):
         myStr = "[Severity Dice, Honor]" + " [" + str(self.data[0])
         for a in self.data[1:]:
@@ -205,7 +202,6 @@
         result = int(random.uniform(1,self.data[num].sides+1))
         self.data[num].value += (((result - 1) * neg) + self.hon)
         self.data[num].history.append(((result - 1) * neg) + self.hon)
-        if result >= self.data[num].sides:
-            self.crit_chain(num,1)
-        if result == 1:
-            self.crit_chain(num,-1)
+        if result >= self.data[num].sides: self.crit_chain(num,1)
+        if result == 1: self.crit_chain(num,-1)
+
--- a/orpg/dieroller/rollers/hero.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/hero.py	Sat Jun 12 03:50:37 2010 -0500
@@ -29,11 +29,10 @@
 #
 # v.1 original release DJM
 
-__version__ = "$Id: hero.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: hero.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from time import time, clock
 import random
-
 from std import std
 from orpg.dieroller.base import *
 
@@ -45,7 +44,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
 
     def k(self,mod):
         return herok(self,mod)
@@ -73,7 +71,6 @@
         self.cv = cv
         self.mod = mod
 
-
     def __str__(self):
         myStr = "[" + str(self.data[0])
         for a in self.data[1:]:
@@ -110,15 +107,10 @@
         modSum = self.sum()-self.mod
         myStr += " = (" + str(modSum) + ")"
         myStr += " vs " + str(self.sk)
-
-        if self.is_success():
-            myStr += " or less <font color='#ff0000'>Success!"
-        else:
-            myStr += " or less <font color='#ff0000'>Failure!"
-
+        if self.is_success(): myStr += " or less <font color='#ff0000'>Success!"
+        else: myStr += " or less <font color='#ff0000'>Failure!"
         Diff = self.sk - modSum
         myStr += " by " + str(Diff) +" </font>"
-
         return myStr
 
 class herok(std):
@@ -230,3 +222,4 @@
         myStr += " <b>Body</b> and "
         myStr += "(<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) <b>Stun</b>"
         return myStr
+
--- a/orpg/dieroller/rollers/mythos.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/mythos.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,9 +23,9 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-# Description: WOD die roller
+# Description: Mythos die roller
 #
 # Targetthr is the Threshhold target
 # for compatibility with Mage die rolls.
@@ -34,7 +34,7 @@
 from std import std
 from orpg.dieroller.base import *
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 class mythos(std):
@@ -85,7 +85,7 @@
             else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
         return myStr
 
-    def non_stdDie(self, s): ## Puu-san
+    def non_stdDie(self, s):
         num_sides = s.split('v')
         if len(num_sides) > 1: 
             num_sides; num = num_sides[0]; sides = num_sides[1]
--- a/orpg/dieroller/rollers/runequest.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/runequest.py	Sat Jun 12 03:50:37 2010 -0500
@@ -52,7 +52,7 @@
 #  o Added Sorcery Fumble table to sorcery spell roller
 #
 
-__version__ = "$Id: runequest.py,v 1.4 2006/11/15 12:11:22 digitalxero Exp $"
+__version__ = "$Id: runequest.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from time import time, clock
 import random
@@ -68,8 +68,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
     def skill(self,sk,mod,ma):
         return rqskill(self,sk,mod,ma)
 
@@ -112,24 +110,20 @@
 
     def __str__(self):
         myStr = "Unrestricted Training"
-
         if self.s == 0:
             myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             myStr = "Training: "
-
             while self.s < self.f and self.s < 75:
                 cost   += self.s * 5
                 time   += self.s * 1
                 self.s += random.uniform(1,4) + 1
-
             myStr  = "Training completed:\n"
             myStr += "\tCost(" + str(int(cost)) + ")\n"
             myStr += "\tTime(" + str(int(time)) + ")\n"
             myStr += "\tSkill(" + str(int(self.s)) + ")"
-
         return myStr
 
 
@@ -150,30 +144,24 @@
 
     def __str__(self):
         myStr = ""
-
         if self.sk == 0 and self.cost >= 50:
             myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             icost = self.sk * 5
-
             myStr = "Training: "
-
             while (cost + icost) < self.cost:
                 if self.sk >= 75:
                     break
-
                 cost += icost
                 time += self.sk * 1
                 self.sk += random.uniform(1,4) + 1
                 icost = self.sk * 5
-
             myStr  = "Training completed: "
             myStr += "Cost(" + str(int(cost)) + ") "
             myStr += "Time(" + str(int(time)) + ") "
             myStr += "Skill(" + str(int(self.sk)) + ")"
-
         return myStr
 
 
@@ -194,30 +182,24 @@
 
     def __str__(self):
         myStr = ""
-
         if self.sk == 0 and self.time >= 20:
             myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             itime = self.sk * 1
-
             myStr = "Trainingsss: "
-
             while (time + itime) < self.time:
                 if self.sk >= 75:
                     break
-
                 cost += self.sk * 5
                 time += itime
                 self.sk += random.uniform(1,4) + 1
                 itime = self.sk * 5
-
             myStr  = "Training completed: "
             myStr += "Cost(" + str(int(cost)) + ") "
             myStr += "Time(" + str(int(time)) + ") "
             myStr += "Skill(" + str(int(self.sk)) + ")"
-
         return myStr
 
 #  RQ Skill Roll
@@ -281,7 +263,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font></b>"
         elif self.is_critical():
@@ -294,10 +275,8 @@
             myStr += " <font color=blue>Success!</font>"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 #
@@ -341,7 +320,6 @@
         return (  self.sum() >= final_fum )
 
     def __str__(self):
-
         # get fumble roll result in case needed
         fum_roll = random.randint(1,100)
 
@@ -359,7 +337,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif self.is_critical() and self.is_riposte():
@@ -378,10 +355,8 @@
             myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 # RQ Dodge Roll
@@ -424,7 +399,6 @@
         return (  self.sum() >= final_fum )
 
     def __str__(self):
-
         # get fumble roll result in case needed
         fum_roll = random.randint(1,100)
 
@@ -442,7 +416,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif self.is_critical() and self.is_riposte():
@@ -461,14 +434,11 @@
             myStr += " <font color=blue>Success!</font> Damage dodged</b>"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 
-
 #
 # RQ Attack Roll
 #
@@ -535,7 +505,6 @@
             myStr += "<B>Head</B>"
         hit_loc = myStr
 
-
         # get normal damage in case needed
         norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
         norm_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
@@ -563,7 +532,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif (self.is_supercritical() and self.is_success()):
@@ -578,7 +546,6 @@
             myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
         else:
             myStr += " <font color=red>Failure!</font>"
-
         return myStr
 
 #
@@ -691,6 +658,5 @@
         myStr += "Intensity(-3):["      + str( self.int      ) + "], "
         myStr += "Accelerate(-5):["     + str( self.acc      ) + "], "
         myStr += "Multispell(-10):["    + str( self.mlt      ) + "] ---"
-
         return myStr
 
--- a/orpg/dieroller/rollers/savage.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/savage.py	Sat Jun 12 03:50:37 2010 -0500
@@ -19,7 +19,7 @@
 # Permission was granted by Pinnacle to reprint the result descriptions from their tables on Apr 20, 2006 by Simon Lucas
 #
 
-__version__ = "$Id: savage.py,v 1.2 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: savage.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import string
 from random import *
--- a/orpg/dieroller/rollers/std.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/std.py	Sat Jun 12 03:50:37 2010 -0500
@@ -3,8 +3,8 @@
 class std(die_base):
     name = "std"
 
-    def __init__(self,source=[]):
-        die_base.__init__(self,source)
+    def __init__(self, source=[]):
+        die_base.__init__(self, source)
 
     #  Examples of adding member functions through inheritance.
 
@@ -19,30 +19,27 @@
         result.reverse()
         return result
 
-    def takeHighest(self,num_dice):
+    def takeHighest(self, num_dice):
         return self.descending()[:num_dice]
 
     def takeLowest(self,num_dice):
         return self.ascending()[:num_dice]
 
-    def extra(self,num):
+    def extra(self, num):
         for i in range(len(self.data)):
             if self.data[i].lastroll() >= num:
                 self.data[i].extraroll()
         return self
 
-    def open(self,num):
-        if num <= 1:
-            self
+    def open(self, num):
+        if num <= 1: self
         done = 1
         for i in range(len(self.data)):
             if self.data[i].lastroll() >= num:
                 self.data[i].extraroll()
                 done = 0
-        if done:
-            return self
-        else:
-            return self.open(num)
+        if done: print self; return self
+        else: return self.open(num)
 
     def minroll(self,min):
         for i in range(len(self.data)):
@@ -50,13 +47,12 @@
                 self.data[i].roll(min)
         return self
 
-    def each(self,mod):
+    def each(self, mod):
         mod = int(mod)
         for i in range(len(self.data)):
             self.data[i].modify(mod)
         return self
 
-
     def vs(self, target):
         for dn in self.data:
             dn.target = target
@@ -72,12 +68,10 @@
         for dn in self.data:
             setValue = reduce( lambda x, y : int(x)+int(y), dn.history )
             if dn.target:
-                if setValue >= dn.target:
-                    retValue += 1
-
+                for dv in dn.history:
+                    if int(dv) >= dn.target: retValue += 1
             else:
                 retValue += setValue
-
         return retValue
 
-die_rollers.register(std)
\ No newline at end of file
+die_rollers.register(std)
--- a/orpg/dieroller/rollers/trinity.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/trinity.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,7 +23,7 @@
 # Author: Jacob Matthew, Talisan Creations
 # Maintainer:
 # Version:
-#   $Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $
+#   $Id: trinity.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Aeon Trinity die roller
 # Modified from the WoD dieroller "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
@@ -32,7 +32,7 @@
 # Threshhold addition by robert t childers
 # Threshhold functionality removed, some tags remain in code.
 
-__version__ = "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
+__version__ = "$Id: trinity.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
@@ -85,4 +85,4 @@
 
         return myStr
 
-die_rollers.register(trinity)
\ No newline at end of file
+die_rollers.register(trinity)
--- a/orpg/dieroller/rollers/wfrpg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wfrpg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,13 +23,13 @@
 # Author: Prof. Ebral, TaS (Traipse)
 # Maintainer:
 # Version:
-#   $Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $
+#   $Id: wfrpg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Warhammer Fantasy Roleplay Dice Roller die roller
 # Comissioned by Puu-san
 #
 
-__version__ = "$Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $"
+__version__ = "$Id: wfrpg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 import random
--- a/orpg/dieroller/rollers/wod.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wod.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,7 +23,7 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: WOD die roller
 #
@@ -31,7 +31,7 @@
 # for compatibility with Mage die rolls.
 # Threshhold addition by robert t childers
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
--- a/orpg/dieroller/rollers/wodex.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wodex.py	Sat Jun 12 03:50:37 2010 -0500
@@ -34,7 +34,7 @@
 from std import std
 from orpg.dieroller.base import *
 
-__version__ = "$Id: wodex.py,v 1.9 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: wodex.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 class wodex(std):
     name = "wodex"
--- a/orpg/dieroller/utils.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/utils.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,12 +22,12 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $
+#   $Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: Classes to help manage the die roller
 #
 
-__version__ = "$Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $"
+__version__ = "$Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp  Exp $"
 
 import re
 
@@ -56,8 +56,7 @@
         return die_rollers.keys()
 
     def stdDieToDClass(self, match):
-        s = match.group(0)
-        self.mod = str(match.string[len(s):])
+        s = match.group(0); self.eval = str(match.string)
         num_sides = s.split('d')
         if len(num_sides) > 1: 
             num_sides; num = num_sides[0]; sides = num_sides[1]
@@ -66,13 +65,17 @@
                 if int(num) > 100 or int(sides) > 10000: return None
             except: pass
             ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
-                    sides.strip(), '))'+self.mod]
-            s =  ''.join(ret); s = str(eval(s)); return s ## Moved eval here for portability.
+                    sides.strip(), '))']
+            s =  ''.join(ret)
+            self.eval = s
+            return s
+
         ## Portable Non Standard Die Characters #Prof-Ebral
-        else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); self.mod = ''; return s
+        else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); return s
 
     #  Use this to convert ndm-style (3d6) dice to d_base format
     def convertTheDieString(self,s):
+        self.result = ''
         reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+")
         (result, num_matches) = reg.subn(self.stdDieToDClass, s)
         if num_matches == 0 or result is None:
@@ -83,15 +86,19 @@
                 test = eval(s2)
                 return s2
             except Exception, e: print e; pass"""
+            self.result = result
             try: return self.do_math(s)
             except: pass
         return result
 
     def do_math(self, s):
-        self.mod = ''
         return str(eval(s))
 
     def proccessRoll(self, s):
-        v = str(self.convertTheDieString(s))
-        return v[:len(v)-len(self.mod)]
+        v = self.convertTheDieString(s)
+        try: b = str(eval(v))
+        except: 
+            if v == self.eval: b = s
+            else: b = str(v) ##Fail safe for non standard dice.
+        return b
 
--- a/orpg/gametree/gametree.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/gametree.py	Sat Jun 12 03:50:37 2010 -0500
@@ -45,8 +45,9 @@
 from orpg.dirpath import dir_struct
 from nodehandlers import core
 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
@@ -60,6 +61,12 @@
 from xml.etree.ElementTree import fromstring, tostring, XML, iselement
 from xml.parsers.expat import ExpatError
 
+def exists(path):
+    try:
+        os.stat(path)
+        return True
+    except: return False
+
 STD_MENU_DELETE = wx.NewId()
 STD_MENU_DESIGN = wx.NewId()
 STD_MENU_USE = wx.NewId()
@@ -206,9 +213,9 @@
             self.EditLabel(curSelection)
         evt.Skip()
    
-    def locate_valid_tree(self, error, msg): ## --Snowdog 3/05
+    def locate_valid_tree(self, error, msg, filename): ## --Snowdog 3/05
         """prompts the user to locate a new tree file or create a new one"""
-        response = wx.MessageDialog(self, msg, error, wx.YES|wx.NO|wx.ICON_ERROR)
+        response = wx.MessageBox(msg, error, wx.YES|wx.NO|wx.ICON_ERROR)
         if response == wx.YES:
             file = None
             dlg = wx.FileDialog(self, "Locate Gametree file", dir_struct["user"],
@@ -221,6 +228,7 @@
             else: self.load_tree(file)
             return
         else:
+            copyfile(dir_struct['template']+'default_tree.xml', filename)
             validate.config_file("tree.xml","default_tree.xml")
             self.load_tree(error=1)
             return
@@ -234,24 +242,25 @@
             self.locate_valid_tree("Gametree Error", emsg)
             return
         try:
+            self.xml_root = False
             tree = parse(filename)
             self.xml_root = tree.getroot()
-        except:
-            self.xml_root = None
-
+        except: self.xml_root = False
         if not self.xml_root:
-            os.rename(filename,filename+".corrupt")
+            count = 1
+            while exists(filename[:len(filename)-4]+'-'+str(count)+'.xml'): count += 1
+            corrupt_tree = filename[:len(filename)-4]+'-'+str(count)+'.xml'
+            copyfile(filename, corrupt_tree)
             emsg = "Your gametree is being regenerated.\n\n"\
                  "To salvage a recent version of your gametree\n"\
-                 "exit OpenRPG and copy the lastgood.xml file in\n"\
+                 "exit OpenRPG and copy the one of the tree-# files in\n"\
                  "your myfiles directory to "+filename+ "\n"\
                  "in your myfiles directory.\n\n"\
                  "lastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.\n\n"\
                  "Would you like to select a different gametree file to use?\n"\
                  "(Selecting 'No' will cause a new default gametree to be generated)"
-            self.locate_valid_tree("Corrupt Gametree!", emsg)
+            self.locate_valid_tree("Corrupt Gametree!", emsg, filename)
             return
-
         if self.xml_root.tag != "gametree":
             emsg = filename+" does not appear to be a valid gametree file.\n\n"\
                  "Would you like to select a different gametree file to use?\n"\
@@ -286,8 +295,22 @@
 
         except Exception, e:
             logger.exception(traceback.format_exc())
-            wx.MessageBox("Corrupt Tree!\nYour game tree is being regenerated. To\nsalvage a recent version of your gametree\nexit OpenRPG and copy the lastgood.xml\nfile in your myfiles directory\nto "+filename+ "\nin your myfiles directory.\nlastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.")
-            os.rename(filename,filename+".corrupt")
+
+            count = 1
+            while exists(filename[:len(filename)-4]+'-'+str(count)+'.xml'): count += 1
+            corrupt_tree = filename[:len(filename)-4]+'-'+str(count)+'.xml'
+            copyfile(filename, corrupt_tree)
+            wx.MessageBox("Your gametree is being regenerated.\n\n"\
+                 "To salvage a recent version of your gametree\n"\
+                 "exit OpenRPG and copy the one of the tree-# files in\n"\
+                 "your myfiles directory to "+filename+ "\n"\
+                 "in your myfiles directory.\n\n"\
+                 "lastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.\n\n")
+
+            count = 1
+            while exists(filename[:len(filename)-4]+'-'+str(count)+'.xml'): count += 1
+            corrupt_tree = filename[:len(filename)-4]+'-'+str(count)+'.xml'
+            copyfile(filename, corrupt_tree)
             validate.config_file("tree.xml","default_tree.xml")
             self.load_tree(error=1)
     
@@ -675,7 +698,7 @@
             family_tree.append(parent)
         return family_tree
     
-    def load_xml(self, xml_element, parent_node, prev_node=None):
+    def load_xml(self, xml_element, parent_node, prev_node=None, drag_drop=False):
         if parent_node == self.root:
             self.tree_map[xml_element.get('name')] = {}
             self.tree_map[xml_element.get('name')]['node'] = xml_element
@@ -698,6 +721,8 @@
         if prev_node:
             if prev_node == parent_node: new_tree_node = self.PrependItem(parent_node, name, i, i)
             else: new_tree_node = self.InsertItem(parent_node, prev_node, name, i, i)
+        elif drag_drop:
+            new_tree_node = self.InsertItemBefore(parent_node, 0, name, i)
         else: new_tree_node = self.AppendItem(parent_node, name, i, i)
 
         logger.debug("Node Added to tree")
@@ -804,7 +829,7 @@
         self.rename_flag = 0
         if txt != "":
             obj = self.GetPyData(item)
-            obj.xml_root.setAttribute('name',txt)
+            obj.xml_root.set('name',txt)
         else: evt.Veto()
     
     def on_label_begin(self, evt):
--- a/orpg/gametree/nodehandlers/StarWarsd20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/StarWarsd20.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis; Mark Twombley
 # Maintainer: Mark Twombley
 # Version:
-#   $Id: StarWarsd20.py,v 1.18 2006/11/15 12:11:23 digitalxero Exp $
+#   $Id: StarWarsd20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the StarWarsd20 nodehanlers
 #
 
-__version__ = "$Id: StarWarsd20.py,v 1.18 2006/11/15 12:11:23 digitalxero Exp $"
+__version__ = "$Id: StarWarsd20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from containers import *
--- a/orpg/gametree/nodehandlers/chatmacro.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/chatmacro.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: chatmacro.py,v 1.15 2006/11/15 12:11:23 digitalxero Exp $
+#   $Id: chatmacro.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the form based nodehanlers
 #
 
-__version__ = "$Id: chatmacro.py,v 1.15 2006/11/15 12:11:23 digitalxero Exp $"
+__version__ = "$Id: chatmacro.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 
@@ -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',"<br />")
+        txt = string.replace(self.xml.find('text').text,'\n',"<br />")
         return "<P><b>"+title+":</b><br />"+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)
@@ -98,6 +94,6 @@
         txt = self.text[id].GetValue()
         if txt == "": return
         if id == P_TITLE:
-            self.handler.xml.setAttribute('name',txt)
+            self.handler.xml.set('name',txt)
             self.handler.rename(txt)
         elif id == P_BODY: self.handler.set_text(txt)
--- a/orpg/gametree/nodehandlers/containers.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/containers.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: containers.py,v 1.43 2007/08/08 19:17:17 digitalxero Exp $
+#   $Id: containers.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the container nodehandlers
 #
@@ -67,11 +67,11 @@
         drag_obj = self.tree.drag_obj
         if drag_obj == self or self.tree.is_parent_node(self.mytree_node,drag_obj.mytree_node): return
         opt = wx.MessageBox("Add node as child?","Container Node",wx.YES_NO|wx.CANCEL)
+        prev_sib = self.tree.GetPrevSibling(drag_obj.mytree_node)
         if opt == wx.YES:
             drop_xml = self.tree.drag_obj.delete()
             self.xml.insert(0, drop_xml)
-            self.tree.load_xml(drop_xml, self.mytree_node)
-            self.tree.Expand(self.mytree_node)
+            self.tree.load_xml(drop_xml, self.mytree_node, drag_drop=True)
         elif opt == wx.NO: node_handler.on_drop(self,evt)
 
     def gen_html(self, treenode, evt):
@@ -245,7 +245,6 @@
         parent.SetSize(self.GetBestSize())
         self.Bind(wx.EVT_TEXT, self.on_text, id=1)
 
-
     def on_text(self,evt):
         txt = self.title.GetValue()
         if txt != "":
@@ -281,19 +280,19 @@
         container_handler.on_drop(self,evt)
 
     def build_splitter_wnd(self, parent, mode):
+        self.parent = parent
         self.split = self.xml.get("horizontal")
-        self.pane = splitter_panel(parent, self)
+        self.pane = splitter_panel(parent, self, mode)
+        self.frame = self.pane.frame
         self.splitter = MultiSplitterWindow(self.pane, -1, 
                         style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH|wx.SP_NO_XP_THEME)
+        self.splitter.parent = self
         if self.split == '1': self.splitter.SetOrientation(wx.VERTICAL)
         else: self.splitter.SetOrientation(wx.HORIZONTAL)
-        self.bestSizex = -1
-        self.bestSizey = -1
         self.tree.traverse(self.mytree_node, self.doSplit, mode, False) 
-        self.pane.sizer.Add(self.splitter, 1, wx.EXPAND)
-        if mode != 1: self.pane.hozCheck.Hide()
-        self.pane.SetSize((self.bestSizex, self.bestSizey))
-        self.pane.Layout()
+        self.pane.sizer.Add(self.splitter, -1, wx.EXPAND)
+        self.pane.SetAutoLayout(True)
+        self.pane.Fit()
         parent.SetSize(self.pane.GetSize())
         return self.pane
 
@@ -301,41 +300,40 @@
         node = self.tree.GetPyData(treenode)
         if mode == 1: tmp = node.get_design_panel(self.splitter)
         else: tmp = node.get_use_panel(self.splitter)
-        if self.split == '1':
-            sash = tmp.GetBestSize()[1]+1
-            self.bestSizey += sash+11
-            if self.bestSizex < tmp.GetBestSize()[0]: self.bestSizex = tmp.GetBestSize()[0]+10
-        else:
-            sash = tmp.GetBestSize()[0]+1
-            self.bestSizex += sash
-            if self.bestSizey < tmp.GetBestSize()[1]: self.bestSizey = tmp.GetBestSize()[1]+31
+        if self.split == '1': sash = self.frame.GetSize()[1]/len(self.xml.findall('nodehandler'))
+        else: sash = self.frame.GetSize()[0]/len(self.xml.findall('nodehandler'))
         self.splitter.AppendWindow(tmp, sash)
+
     def get_size_constraint(self):
         return 1
 
 class splitter_panel(wx.Panel):
-    def __init__(self, parent, handler):
+    def __init__(self, parent, handler, mode):
         wx.Panel.__init__(self, parent, -1)
+        self.parent = parent
         self.handler = handler
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
-
-        self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
-        hoz = self.handler.xml.get("horizontal")
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        if mode == 0: self.title = wx.StaticText(self, 1, handler.xml.get('name'))
+        elif mode == 1: self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
+        self.frame = self.GetParent()
+        while self.frame.GetName() != 'frame':
+            self.frame = self.frame.GetParent()
 
-        if hoz == '1': self.hozCheck.SetValue(True)
-        else: self.hozCheck.SetValue(False)
+        if mode == 1:
+            self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
+            hoz = self.handler.xml.get("horizontal")
+            if hoz == '1': self.hozCheck.SetValue(True)
+            else: self.hozCheck.SetValue(False)
 
-        sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
-        sizer.Add(self.title, 0)
-        sizer.Add(self.hozCheck, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,0))
+        if mode == 1: self.sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.sizer.Add(self.title, 0)
+        if mode == 1: self.sizer.Add(self.hozCheck, 0, wx.EXPAND)
+        self.sizer.Add(wx.Size(10,0))
 
-        self.sizer = sizer
         self.SetSizer(self.sizer)
         self.SetAutoLayout(True)
         self.Bind(wx.EVT_TEXT, self.on_text, id=1)
-        self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
+        if mode == 1: self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
 
     def on_check_box(self,evt):
         state = self.hozCheck.GetValue()
--- a/orpg/gametree/nodehandlers/core.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/core.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,14 +21,15 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: core.py,v 1.49 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: core.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the core nodehanlers
 #
 
-__version__ = "$Id: core.py,v 1.49 2007/12/07 20:39:48 digitalxero Exp $"
+__version__ = "$Id: core.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from nodehandler_version import NODEHANDLER_VERSION
+from orpg.tools.InterParse import Parse
 
 try:
     from orpg.orpg_windows import *
@@ -54,7 +55,6 @@
         self.xml = xml
         self.mytree_node = tree_node
         self.tree = component.get('tree')
-        #self.tree = component.get('tree_fs')
         self.frame = component.get('frame')
         self.chat = component.get('chat')
         self.drag = True
@@ -282,7 +282,7 @@
     def get_html_panel(self,parent):
         html_str = "<html><body bgcolor=\"#FFFFFF\" >"+self.tohtml()+"</body></html>"
         wnd = wx.html.HtmlWindow(parent,-1)
-        html_str = self.chat.ParseDice(html_str)
+        html_str = Parse.Dice(html_str)
         wnd.SetPage(html_str)
         return wnd
 
@@ -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)
 
 
@@ -386,7 +387,8 @@
 
     def on_ldclick(self,evt):
         file_name = self.file_node.get("name")
-        self.tree.insert_xml(open(orpg.dirpath.dir_struct["nodes"] + file_name,"r").read())
+        try: self.tree.insert_xml(open(orpg.dirpath.dir_struct["nodes"] + file_name,"r").read())
+        except: wx.MessageBox('Invalid File', 'Error')
         return 1
 
     def on_design(self,evt):
--- a/orpg/gametree/nodehandlers/d20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/d20.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: d20.py,v 1.30 2007/05/22 00:50:57 digitalxero Exp $
+#   $Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the d20 nodehanlers
 #
 
-__version__ = "$Id: d20.py,v 1.30 2007/05/22 00:50:57 digitalxero Exp $"
+__version__ = "$Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from containers import *
@@ -34,6 +34,7 @@
 from xml.etree.ElementTree import ElementTree, Element, iselement
 from xml.etree.ElementTree import fromstring, tostring, parse, XML
 from orpg.tools.orpg_log import debug
+from orpg.tools.InterParse import Parse
 
 D20_EXPORT = wx.NewId()
 ############################
@@ -991,9 +992,9 @@
             for i in range( 0, len( bab ) ):
                 if bab[i] > 0 or i == 0:
                     attack_roll_str = '[1d20%+d]' % (bab[i] + attack_mod)
-                    attack_roll_parsed = self.chat.ParseDice( attack_roll_str )
+                    attack_roll_parsed = Parse.Dice( attack_roll_str )
                     damage_roll_str = '[%dd%d%+d%s]' % (num_damage_dice, damage_die, damage_mod, extra_damage)
-                    damage_roll_parsed = self.chat.ParseDice( damage_roll_str )
+                    damage_roll_parsed = Parse.Dice( damage_roll_str )
                     txt = '%s (%s): %s ===> Damage: %s' \
                           % (name, bab_attributes[i], attack_roll_parsed, damage_roll_parsed)
                     self.chat.Post( txt, True, True )
--- a/orpg/gametree/nodehandlers/dnd3e.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/dnd3e.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis & Digitalxero
 # Maintainer: leadb
 # Version:
-#   $Id: dnd3e.py,v 1.33 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: dnd3e.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the dnd3e nodehanlers
 #
@@ -261,7 +261,6 @@
         n_list = self.xml.getchildren()
         html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>"
         for n in n_list:
-            debug(n)
             html_str += "<B>"+n.tag.capitalize() +":</B> "
             html_str += n.text + ", "
         html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
@@ -377,12 +376,10 @@
             value = self.lang.GetValue()
         for node in self.n_list:
             if node.tag == nodeName:
-                debug(node)
                 node.text = value
 
     def saveMoney(self, row, col):
         value = self.grid.GetCellValue(row, col)
-        debug(self.n_list[row])
         self.n_list[row].text = value
 
     def on_cell_change(self, evt):
@@ -2271,12 +2268,10 @@
                 self.xml.remove(self.n_list[i])
 
     def on_add(self,evt):
-        debug()
         if not self.temp_dom:
             tree = parse(dir_struct["dnd3e"]+"dnd3espells.xml")
             xml_dom = tree.getroot()
             self.temp_dom = xml_dom
-        debug(self.temp_dom)
         f_list = self.temp_dom.findall('spell')
         opts = []
         #lvl = int(dnd3e_char_child.get_char_lvl('level'))
@@ -2667,12 +2662,10 @@
                 self.xml.remove(self.n_list[i])
 
     def on_add(self,evt):
-        debug()
         if not self.temp_dom:
             tree = parse(dir_struct["dnd3e"]+"dnd3epowers.xml")
             xml_dom = tree.getroot()
             self.temp_dom = xml_dom
-        debug(self.temp)
         f_list = self.temp_dom.findall('power')
         opts = []
         for f in f_list:
--- a/orpg/gametree/nodehandlers/forms.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/forms.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,18 +21,19 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: forms.py,v 1.53 2007/04/21 23:00:51 digitalxero Exp $
+#   $Id: forms.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the form based nodehanlers
 #
 
-__version__ = "$Id: forms.py,v 1.53 2007/04/21 23:00:51 digitalxero Exp $"
+__version__ = "$Id: forms.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 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
 
 def bool2int(b):
     #in wxPython 2.5+, evt.Checked() returns True or False instead of 1.0 or 0.
@@ -108,11 +109,11 @@
 
 F_HEIGHT = wx.NewId()
 F_WIDTH = wx.NewId()
-class form_edit_panel(wx.Panel):
+class form_edit_panel(ScrolledPanel):
     def __init__(self, parent, handler):
-        wx.Panel.__init__(self, parent, -1)
+        ScrolledPanel.__init__(self, parent, wx.ID_ANY, style=wx.NO_BORDER|wx.VSCROLL|wx.HSCROLL)
         self.handler = handler
-        sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Form Properties"), wx.VERTICAL)
+        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
         wh_sizer = wx.BoxSizer(wx.HORIZONTAL)
         self.text = {   P_TITLE : wx.TextCtrl(self, P_TITLE, handler.xml.get('name')),
                         F_HEIGHT : wx.TextCtrl(self, F_HEIGHT, handler.xml.get('height')),
@@ -127,15 +128,17 @@
         wh_sizer.Add(wx.Size(10,10))
         wh_sizer.Add(self.text[F_HEIGHT], 0, wx.EXPAND)
 
-        sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
-        sizer.Add(self.text[P_TITLE], 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wh_sizer,0,wx.EXPAND)
+        self.main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.main_sizer.Add(self.text[P_TITLE], 0, wx.EXPAND)
+        self.main_sizer.Add(wx.Size(10,10))
+        self.main_sizer.Add(wh_sizer,0,wx.EXPAND)
+        handler.tree.traverse(handler.mytree_node, self.create_child_wnd, None, False)
 
-        self.SetSizer(sizer)
+        self.SetSizer(self.main_sizer)
         self.SetAutoLayout(True)
+        self.SetupScrolling()
+        parent.SetSize(self.GetSize())
         self.Fit()
-        parent.SetSize(self.GetBestSize())
 
         self.Bind(wx.EVT_TEXT, self.on_text, id=P_TITLE)
         self.Bind(wx.EVT_TEXT, self.on_text, id=F_HEIGHT)
@@ -154,6 +157,14 @@
             if id == F_HEIGHT: self.handler.xml.set("height",txt)
             elif id == F_WIDTH: self.handler.xml.set("width",txt)
 
+    def create_child_wnd(self, treenode, evt):
+        node = self.handler.tree.GetPyData(treenode)
+        panel = node.get_design_panel(self)
+        size = node.get_size_constraint()
+        if panel:
+            self.main_sizer.Add(panel, size, wx.EXPAND)
+            self.main_sizer.Add(wx.Size(10,10))
+
 ##########################
 ## control handler
 ##########################
@@ -262,16 +273,16 @@
 
     def on_send(self, evt):
         txt = self.text.GetValue()
-        txt = self.chat.ParseMap(txt, self.handler.xml)
-        txt = self.chat.ParseParent(txt, self.handler.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.handler.xml)
         if not self.handler.is_raw_send():
-            self.chat.ParsePost(self.handler.tohtml(), True, True)
+            Parse.Post(self.handler.tohtml(), self.chat, True, True)
             return 1
         actionlist = txt.split("\n")
         for line in actionlist:
+            line = Parse.ParseLogic(line, self.handler.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    self.chat.ParsePost(line, True, True)
+                    Parse.Post(line, self.chat, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -319,7 +330,7 @@
             sizer_style=wx.EXPAND
             text_style = 0
             multi = 0
-        self.text = wx.TextCtrl(self, F_TEXT, handler.get_value(),style=text_style)
+        self.text = wx.TextCtrl(self, F_TEXT, handler.get_value() or '',style=text_style)
         sizer.Add(wx.Size(5,0))
         sizer.Add(self.text, multi, sizer_style)
         self.SetSizer(sizer)
@@ -595,18 +606,16 @@
 
     def on_send_to_chat(self, evt):
         txt = self.get_selected_text()
-        txt = self.chat.ParseMap(txt, self.xml)
-        txt = self.chat.ParseParent(txt, self.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.xml)
         if not self.is_raw_send():
-            self.chat.ParsePost(self.tohtml(), True, True)
+            Parse.Post(self.tohtml(), self.chat, True, True)
             return 1
         actionlist = self.get_selections_text()
         for line in actionlist:
-            line = self.chat.ParseMap(line, self.xml)
-            line = self.chat.ParseParent(line, self.xml.get('map'))
+            line = Parse.ParseLogic(line, self.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    self.chat.ParsePost(line, True, True)
+                    Parse.Post(line, self.chat, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -620,6 +629,7 @@
 class listbox_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
+        #ScrolledPanel.__init__(self, parent, wx.ID_ANY, style=wx.NO_BORDER|wx.VSCROLL|wx.HSCROLL)
         self.handler = handler
         self.chat = handler.chat
         opts = []
@@ -637,8 +647,8 @@
             if self.list.GetSize()[0] > 200:
                 self.list.Destroy()
                 self.list = wx.ComboBox(self, F_LIST, cur_opt, size=(200, -1), choices=opts, style=wx.CB_READONLY)
-        elif type == L_LIST: self.list = wx.ListBox(self,F_LIST,choices=opts)
-        elif type == L_RADIO: self.list = wx.RadioBox(self,F_LIST,label,choices=opts,majorDimension=3)
+        elif type == L_LIST: self.list = wx.ListBox(self, F_LIST, choices=opts)
+        elif type == L_RADIO: self.list = wx.RadioBox(self, F_LIST, label, choices=opts, majorDimension=3)
         elif type == L_CHECK:
             self.list = wx.CheckListBox(self,F_LIST,choices=opts)
             self.set_checks()
@@ -650,17 +660,17 @@
         else: sizer = wx.BoxSizer(wx.VERTICAL)
 
         if type != L_RADIO:
-            sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
-            sizer.Add(wx.Size(5,0))
-        sizer.Add(self.list, 1, wx.EXPAND)
+            sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND|wx.ALL)
+        sizer.Add(self.list, 1, wx.EXPAND|wx.ALL)
         if handler.has_send_button():
-            sizer.Add(wx.Button(self, F_SEND, "Send"), 0, wx.EXPAND)
+            sizer.Add(wx.Button(self, F_SEND, "Send"), 0, wx.EXPAND|wx.ALL)
             self.Bind(wx.EVT_BUTTON, self.handler.on_send_to_chat, id=F_SEND)
         self.sizer = sizer
         self.SetSizer(sizer)
         self.SetAutoLayout(True)
+        #self.SetupScrolling()
+        #parent.SetSize(self.GetBestSize())
         self.Fit()
-        parent.SetSize(self.GetBestSize())
 
         if type == L_DROP: self.Bind(wx.EVT_COMBOBOX, self.on_change, id=F_LIST)
         elif type == L_LIST: self.Bind(wx.EVT_LISTBOX, self.on_change, id=F_LIST)
@@ -754,7 +764,7 @@
     def on_add(self,evt):
         self.dlg = wx.Frame(self, -1, 'Text', size=(300,150))
         edit_panel = wx.Panel(self.dlg, -1)
-        sizer = wx.GridBagSizer(1, 2)
+        sizer = wx.GridBagSizer(1, 1)
         edit_panel.SetSizer(sizer)
         caption_text = wx.StaticText(edit_panel, -1, 'Caption')
         self.caption_entry = wx.TextCtrl(edit_panel, -1, '')
@@ -764,12 +774,17 @@
         button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
         button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
         sizer.Add(caption_text, (0,0))
-        sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(self.caption_entry, (0,1), span=(1,4), flag=wx.EXPAND)
         sizer.Add(value_text, (1,0))
-        sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(self.value_entry, (1,1), span=(1,4), flag=wx.EXPAND)
         sizer.Add(button_ok, (3,0))
         sizer.Add(button_cancel, (3,1))
         sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+        sizer.AddGrowableCol(3)
+        sizer.AddGrowableRow(2)
+        self.dlg.SetSize((275, 125))
+        self.dlg.SetMinSize((275, 125))
+        self.dlg.Layout()
         self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
         self.Bind(wx.EVT_BUTTON, self.on_add_option, id=wx.ID_OK)
         self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
@@ -883,12 +898,17 @@
             button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
             button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
             sizer.Add(caption_text, (0,0))
-            sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(self.caption_entry, (0,1), span=(1,4), flag=wx.EXPAND)
             sizer.Add(value_text, (1,0))
-            sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(self.value_entry, (1,1), span=(1,4), flag=wx.EXPAND)
             sizer.Add(button_ok, (3,0))
             sizer.Add(button_cancel, (3,1))
             sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+            sizer.AddGrowableCol(3)
+            sizer.AddGrowableRow(2)
+            self.dlg.SetSize((275, 125))
+            self.dlg.SetMinSize((275, 125))
+            self.dlg.Layout()
             self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
             self.Bind(wx.EVT_BUTTON, self.on_edit_ok, id=wx.ID_OK)
             self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
--- a/orpg/gametree/nodehandlers/map_miniature_nodehandler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/map_miniature_nodehandler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Andrew Bennett
 # Maintainer:
 # Version:
-#   $Id: map_miniature_nodehandler.py,v 1.17 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: map_miniature_nodehandler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for miniature images
 #
--- a/orpg/gametree/nodehandlers/minilib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/minilib.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: minilib.py,v 1.28 2007/04/22 22:00:18 digitalxero Exp $
+#   $Id: minilib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for a collection of miniatures.
 #
 
-__version__ = "$Id: minilib.py,v 1.28 2007/04/22 22:00:18 digitalxero Exp $"
+__version__ = "$Id: minilib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 """Nodehandler for collections of miniatures.  User can add, delete, edit
 miniatures as sending them to the map singly or in batches.
@@ -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'
 # <nodehandler name='?' module='minilib' class='minilib_handler'>
 #     <miniature name='?' url='?' unique='?'></miniature>
 # </nodehandler>
@@ -100,11 +90,11 @@
         """
         str = '<table border="2" >'
         str += "<tr><th width='20%'>Label</th><th>Image</th><th width='65%'>URL</th><th>Unique</th></tr>"
-        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,16 +123,16 @@
             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 ) == '': mini.set( key, '0' )
+            if mini.get( key ) == ('' or None): mini.set( key, '0' )
         if add:
             self.add_mini( mini )
             self.add_leaf( mini )
@@ -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("<map action='update'><miniatures>" + msg + "</miniatures></map>")
-            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):
@@ -314,6 +306,11 @@
         self.frame = frame
 
         self.sizer = wx.BoxSizer( wx.VERTICAL )
+
+        self.text = wx.TextCtrl(self, 3, handler.xml.get('name'))
+        self.sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.sizer.Add(self.text, 0, wx.EXPAND)
+
         self.grid = minilib_grid( self, handler )
 
         bbox = wx.BoxSizer( wx.HORIZONTAL )
@@ -333,6 +330,7 @@
         self.SetAutoLayout(True)
         self.Fit()
 
+        self.Bind(wx.EVT_TEXT, self.on_text, id=3)
         self.Bind(wx.EVT_BUTTON, self.add_mini, newMiniBtn)
         self.Bind(wx.EVT_BUTTON, self.del_mini, delMiniBtn)
         self.Bind(wx.EVT_BUTTON, self.send_to_map, addMiniBtn)
@@ -354,7 +352,7 @@
         """Event handler for the 'Add 1' button.  Sends the
         miniature defined by the currently selected row to the map, once.
         """
-        index = self.grid.GetGridCursorRow()
+        index = self.grid.GetSelectedRows()[0] if len(self.grid.GetSelectedRows()) > 0 else 0
         self.handler.send_mini_to_map( self.handler.get_mini( index ) )
 
     def send_group_to_map( self, evt=None ):
@@ -370,10 +368,16 @@
                 try: value = eval( dlg.GetValue() )
                 except: value = 0
                 print 'getting selected index for batch send'
-                index = self.grid.GetGridCursorRow()
+                index = self.grid.GetSelectedRows()[0] if len(self.grid.GetSelectedRows()) > 0 else 0
                 print 'sending batch to map'
                 self.handler.send_mini_to_map( self.handler.get_mini( index ), value )
 
+    def on_text(self, evt):
+        txt = self.text.GetValue()
+        if txt != "":
+            self.handler.xml.set('name',txt)
+            self.handler.rename(txt)
+
 class minilib_grid(wx.grid.Grid):
     """A wxGrid subclass designed for editing game tree miniature library
     nodes.
@@ -392,9 +396,10 @@
         self.AutoSizeColumns()
         self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
         self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.select_cell)
+        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 )
 
@@ -413,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
@@ -421,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 )
 
@@ -433,11 +438,9 @@
         """
         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 )
-            list = self.getList()
-            del list[ pos ]
 
     def on_cell_change( self, evt ):
         """Event handler for cell selection changes. selected row is used
@@ -481,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 )
 
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,15 +21,17 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $
+#   $Id: rpg_grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the grid nodehanlers
 #
 
-__version__ = "$Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $"
+__version__ = "$Id: rpg_grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from forms import *
+from orpg.tools.orpg_log import debug
+from orpg.tools.InterParse import Parse
 
 class rpg_grid_handler(node_handler):
     """ Node handler for rpg grid tool
@@ -87,16 +89,20 @@
                 html_str += "<td >"
                 text = c.text
                 if text == None or text == '': text = '<br />'
+                s = Parse.ParseLogic(text, self.xml)
+                s = Parse.Normalize(s)
+                try: text = str(eval(s))
+                except: text = s
                 html_str += text + "</td>"
             html_str += "</tr>"
         html_str += "</table>"
         return html_str
 
     def get_design_panel(self,parent):
-        return rpg_grid_edit_panel(parent,self)
+        return rpg_grid_edit_panel(parent, self)
 
     def get_use_panel(self,parent):
-        return rpg_grid_panel(parent,self)
+        return rpg_grid_panel(parent, self)
 
     def get_size_constraint(self):
         return 1
@@ -194,7 +200,8 @@
         to begin editing.  Set the focus to the edit control.
         *Must Override*
         """
-        self.startValue = grid.GetTable().GetValue(row, col)
+        #self.startValue = grid.GetTable().GetValue(row, col)
+        self.startValue = grid.get_value(row, col)
         self._tc.SetValue(self.startValue)
         self._tc.SetInsertionPointEnd()
         self._tc.SetFocus()
@@ -213,7 +220,6 @@
         if val != self.startValue:
             changed = True
             grid.GetTable().SetValue(row, col, val) # update the table
-
         self.startValue = ''
         self._tc.SetValue('')
         return changed
@@ -265,11 +271,11 @@
 
 class rpg_grid(wx.grid.Grid):
     """grid for attacks"""
-    def __init__(self, parent, handler):
+    def __init__(self, parent, handler, mode):
         wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
         self.parent = parent
         self.handler = handler
-
+        self.mode = mode
         self.RegisterDataType(wx.grid.GRID_VALUE_STRING, wx.grid.GridCellStringRenderer(),MyCellEditor())
 
         self.rows = handler.grid.findall('row')
@@ -286,7 +292,6 @@
         self.Bind(wx.grid.EVT_GRID_COL_SIZE, self.on_col_size)
         self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_leftdclick)
 
-
     def on_leftdclick(self,evt):
         if self.CanEnableCellControl(): self.EnableCellEditControl()
 
@@ -304,6 +309,7 @@
         cells = self.rows[row].findall('cell')
         cells[col].text = value
         if col == 0: self.handler.refresh_rows()
+        for i in range(0,len(self.rows)): self.refresh_row(i)
 
     def set_col_widths(self):
         cells = self.rows[0].findall('cell')
@@ -313,13 +319,17 @@
                 self.SetColSize(i,size)
             except: continue
 
-    def refresh_row(self,rowi):
+    def refresh_row(self, rowi):
         cells = self.rows[rowi].findall('cell')
         for i in range(0,len(cells)):
             text = cells[i].text
             if text == None or text == '':
                 text = ''
                 cells[i].text = text
+            if self.mode == 0:
+                s = Parse.ParseLogic(text, self.handler.xml)
+                try: text = str(eval(s))
+                except: text = s
             self.SetCellValue(rowi,i,text)
 
     def add_row(self,evt=None):
@@ -359,6 +369,10 @@
         self.DeleteCols(num-1,1)
         self.set_col_widths()
 
+    def get_value(self, row, col):
+        cells = self.rows[row].findall('cell')
+        return cells[col].text
+
 
 G_TITLE = wx.NewId()
 GRID_BOR = wx.NewId()
@@ -366,7 +380,7 @@
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
-        self.grid = rpg_grid(self, handler)
+        self.grid = rpg_grid(self, handler, mode=0)
         label = handler.xml.get('name')
         self.main_sizer = wx.BoxSizer(wx.VERTICAL)
         self.main_sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
@@ -388,7 +402,7 @@
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
         self.parent = parent
-        self.grid = rpg_grid(self,handler)
+        self.grid = rpg_grid(self,handler, mode=1)
         self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Grid"), wx.VERTICAL)
 
         self.title = wx.TextCtrl(self, G_TITLE, handler.xml.get('name'))
@@ -462,6 +476,8 @@
         complete = complete[:len(complete)-2] + '::'+'('+row+','+col+')'+complete[len(complete)-2:]
         col = self.grid.GetGridCursorCol()
         row = self.grid.GetGridCursorRow()
+        temp_value = self.grid.GetCellValue(row, col)
+        complete = temp_value + complete
         self.grid.SetCellValue(row, col, complete)
         cells = self.grid.rows[row].findall('cell')
         cells[col].text = complete
@@ -505,6 +521,8 @@
                 else:
                     col = self.grid.GetGridCursorCol()
                     row = self.grid.GetGridCursorRow()
+                    temp_value = self.grid.GetCellValue(row, col)
+                    complete = temp_value + complete
                     self.grid.SetCellValue(row, col, complete)
                     cells = self.grid.rows[row].findall('cell')
                     cells[col].text = complete
@@ -527,3 +545,15 @@
         if txt != "":
             self.handler.xml.set('name',txt)
             self.handler.rename(txt)
+
+    def refresh_row(self,rowi):
+        cells = self.rows[rowi].findall('cell')
+        for i in range(0,len(cells)):
+            text = cells[i].text
+            #s = component.get('chat').ParseMap(s, self.handler.xml)
+            #try: text = str(eval(s))
+            #except: text = s
+            if text == None or text == '':
+                text = ''
+                cells[i].text = text
+            self.SetCellValue(rowi,i,text)
--- a/orpg/gametree/nodehandlers/voxchat.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/voxchat.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,17 +21,16 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: voxchat.py,v 1.37 2007/05/06 16:42:55 digitalxero Exp $
+#   $Id: voxchat.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for alias.
 #
 
-__version__ = "$Id: voxchat.py,v 1.37 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: voxchat.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import re, os, string, core
 
 from orpg.orpg_windows import *
-import core
 import orpg.tools.scriptkit
 import orpg.tools.predTextCtrl
 import orpg.tools.rgbhex
@@ -53,7 +52,7 @@
     def __init__(self, xml_dom, tree_node):
         core.node_handler.__init__( self, xml_dom, tree_node)
         self.node = xml_dom
-        self.xml = component.get('xml')
+        #self.xml = component.get('xml')
 
     def get_design_panel( self, parent ):
         aliasLib = component.get('alias')
--- a/orpg/main.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/main.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,13 +21,13 @@
 # File: main.py
 # Author: Chris Davis
 # Maintainer:
-# Version:
-#   $Id: main.py,v 1.153 2008/01/24 03:52:03 digitalxero Exp $
+# Version: Traipse 'Ornery-Orc'
+#   $Id: main.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This is the main entry point of the oprg application
 #
 
-__version__ = "$Id: main.py,v 1.154 2009/07/19 03:52:03 madmathlabs Exp $"
+__version__ = "$Id: main.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import *
@@ -50,25 +50,20 @@
 import orpg.mapper.images
 
 import orpg.dieroller.utils
-
-#Update Manager# Un remark if you have Mercurial installed
 import upmana.updatemana
-import upmana.manifest as manifest
+from upmana.manifest import manifest
 
 from orpg.dirpath import dir_struct
-#from orpg.dieroller.utils import DiceManager
 from orpg.tools.settings import settings
 from orpg.tools.validate import validate
 from orpg.tools.passtool import PassTool
 from orpg.tools.orpg_log import logger, crash, debug
 from orpg.tools.metamenus import MenuBarEx
+from orpg.tools.InterParse import Parse
 
 from xml.etree.ElementTree import ElementTree, Element, parse
 from xml.etree.ElementTree import fromstring, tostring
-## Element Tree usage will require users to convert to and from string data quite often until users of older versions update.
-## This is a problem that users of older versions will need to cross as it is both Core and Traipse that will make the change.
-## Older versions have a problem with correct XML.
-from orpg.orpg_xml import xml #to be replaced by etree
+#from orpg.orpg_xml import xml #to be replaced by etree
 
 
 ####################################
@@ -77,7 +72,7 @@
 
 
 class orpgFrame(wx.Frame):
-    
+
     def __init__(self, parent, id, title):
         wx.Frame.__init__(self, parent, id, title, wx.Point(100, 100), wx.Size(600,420), style=wx.DEFAULT_FRAME_STYLE)
         self.validate = component.get("validate")
@@ -167,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()
@@ -207,7 +207,7 @@
                     ['  -'],
                     ['  Tab Styles'],
                     ['    Slanted'],
-                    ['      Colorful', "check"],
+                    #['      Colorful', "check"],
                     ['      Black and White', "check"],
                     ['      Aqua', "check"],
                     ['      Custom', "check"],
@@ -257,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')
@@ -299,7 +300,8 @@
         self.mainmenu.Insert(8, self.traipseSuite, "&Traipse Suite!")
         if menuitem == 'debug':
             if self.debugger.IsShown() == True:
-                self.mainmenu.Replace(8, self.traipseSuite, '&Traipse Suite')
+                self.mainmenu.Remove(8)
+                self.mainmenu.Insert(8, self.traipseSuite, "&Traipse Suite")
             else:
                 self.debugConsole.SetBitmap(wx.Bitmap(dir_struct["icon"] + 'spotlight.png'))
                 self.traipseSuite.RemoveItem(self.debugConsole)
@@ -322,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')
@@ -340,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']
@@ -364,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)
@@ -374,18 +374,15 @@
             if textColor != None: wnd.SetNonActiveTabTextColour(textColor)
             wnd.Refresh()
 
-    
     def OnMB_OpenRPGNewMap(self):
         pass #Not Implemented yet!
 
-    
     def OnMB_OpenRPGTabStylesSlantedColorful(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedColorful"):
             settings.change('TabTheme', 'slanted&colorful')
             self.SetTabStyles("OpenRPGTabStylesSlantedColorful", FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS)
         else: self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", True)
 
-    
     def OnMB_OpenRPGTabStylesSlantedBlackandWhite(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedBlackandWhite"):
             settings.change('TabTheme', 'slanted&bw')
@@ -393,7 +390,6 @@
                 FNB.FNB_VC8, graidentTo=wx.WHITE, graidentFrom=wx.WHITE, textColor=wx.BLACK)
         else: self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", True)
 
-    
     def OnMB_OpenRPGTabStylesSlantedAqua(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedAqua"):
             settings.change('TabTheme', 'slanted&aqua')
@@ -505,7 +501,7 @@
         else: self.updateMana.Show()
 
     def OnMB_DebugConsole(self, evt):
-        self.TraipseSuiteWarnCleanup('debug') ### Beta ###
+        self.TraipseSuiteWarnCleanup('debug')
         if self.debugger.IsShown() == True: self.debugger.Hide()
         else: self.debugger.Show()
 
@@ -514,28 +510,28 @@
         if self.mainmenu.GetMenuState("ToolsLoggingLevelDebug"): lvl |= ORPG_DEBUG
         else: lvl &= ~ORPG_DEBUG
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelNote(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelNote"): lvl |= ORPG_DEBUG
         else: lvl &= ~ORPG_DEBUG
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelInfo(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelInfo"): lvl |= ORPG_INFO
         else: lvl &= ~ORPG_INFO
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelGeneral(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelGeneral"): lvl |= ORPG_GENERAL
         else: lvl &= ~ORPG_GENERAL
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsPasswordManager(self):
         if self.mainmenu.GetMenuState("ToolsPasswordManager"): self.password_manager.Enable()
@@ -630,10 +626,8 @@
         # Update Manager 
         #self.manifest = manifest.ManifestChanges()
         self.updateMana = upmana.updatemana.updaterFrame(self, 
-            "OpenRPG Update Manager 1.0", component, manifest, True)
-        print component.get('upmana-win')
+            "OpenRPG Update Manager 1.2", component, manifest, True)
         component.add('upmana-win', self.updateMana)
-        print component.get('upmana-win')
         logger.debug("Menu Created")
         h = int(xml_dom.get("height"))
         w = int(xml_dom.get("width"))
@@ -685,7 +679,7 @@
         logger.debug("Status Window Created")
 
         # Create and show the floating dice toolbar
-        self.dieToolBar = orpg.tools.toolBars.DiceToolBar(self, callBack = self.chat.ParsePost)
+        self.dieToolBar = orpg.tools.toolBars.DiceToolBar(self, callBack = Parse.Post)
         wndinfo = AUI.AuiPaneInfo()
         menuid = wx.NewId()
         self.mainwindows[menuid] = "Dice Tool Bar"
@@ -757,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
@@ -800,7 +794,7 @@
             temp_wnd = orpg.chat.chatwnd.chat_notebook(parent_wnd, wx.DefaultSize)
             self.chattabs = temp_wnd
             self.chat = temp_wnd.MainChatPanel
-            component.add("chat",self.chat)
+            component.add("chat", self.chat)
 
         elif name == "player":
             temp_wnd = orpg.player_list.player_list(parent_wnd)
@@ -939,10 +933,9 @@
         etreeEl = Element('msg')
         try: etreeEl.append(fromstring(data))
         except: etreeEl.text = data
-        if player: display_name = self.chat.chat_display_name(player)
-        else: display_name = "Server Administrator"
 
-        if etreeEl.text: self.chat.Post(etreeEl.text)
+        display_name = self.chat.chat_display_name(player)
+        if etreeEl.text:self.chat.Post(display_name+etreeEl.text)
 
         for child in etreeEl.getchildren():
             if child.tag == 'tree':
@@ -950,7 +943,6 @@
                     wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                 if dlg.ShowModal() == wx.ID_YES:
                   dlg.Destroy()
-                  debug(child)
                   self.tree.on_receive_data(tostring(child))
                   self.chat.InfoPost(display_name + " has sent you a tree node...")
             elif child.tag == 'map':
@@ -1112,7 +1104,8 @@
 		'Bernhard Bergbauer', 'Chris Blocher', 'David Byron', 'Ben Collins-Sussman', 'Robin Cook', 'Greg Copeland',
 		'Chris Davis', 'Michael Edwards', 'Andrew Ettinger', 'Todd Faris', 'Dj Gilcrease',
         'Christopher Hickman', 'Paul Hosking', 'Brian Manning', 'Scott Mackay', 'Jesse McConnell', 
-		'Brian Osman', 'Rome Reginelli', 'Christopher Rouse', 'Dave Sanders', 'Tyler Starke', 'Mark Tarrabain']
+		'Brian Osman', 'Rome Reginelli', 'Christopher Rouse', 'Dave Sanders', 'Tyler Starke', 'Mark Tarrabain',
+        'David Vrabel']
         for dev in orpg_devs:
             self.About.AppendText(dev+'\n')
 
@@ -1135,7 +1128,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", [])
--- a/orpg/mapper/background.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: background.py,v 1.29 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: background.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: background.py,v 1.29 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: background.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 import thread, urllib, os.path, time, mimetypes
@@ -34,6 +34,7 @@
 from orpg.orpgCore import component
 from orpg.tools.orpg_log import logger
 from orpg.tools.orpg_settings import settings
+from xml.etree.ElementTree import fromstring
 
 ##-----------------------------
 ## background layer
@@ -210,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()
@@ -244,22 +248,21 @@
     def upload(self, postdata, filename, type):
         self.lock.acquire()
         if type == 'Image' or type == 'Texture':
-            url = component.get('settings').get_setting('ImageServerBaseURL')
+            url = settings.get_setting('ImageServerBaseURL')
             file = urllib.urlopen(url, postdata)
             recvdata = file.read()
             file.close()
             try:
-                xml_dom = minidom.parseString(recvdata)._get_documentElement()
-                if xml_dom.nodeName == 'path':
-                    path = xml_dom.getAttribute('url')
+                xml_dom = fromstring(recvdata)
+                if xml_dom.tag == 'path':
+                    path = xml_dom.get('url')
                     path = urllib.unquote(path)
                     if type == 'Image': self.set_image(path, 1)
                     else: self.set_texture(path)
                     self.localPath = filename
                     self.local = True
                     self.localTime = time.time()
-                else:
-                    print xml_dom.getAttribute('msg')
+                else: print xml_dom.get('msg')
             except Exception, e:
                 print e
                 print recvdata
--- a/orpg/mapper/background_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: background_handler.py,v 1.23 2007/03/09 14:17:15 digitalxero Exp $
+#   $Id: background_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Background layer handler
 #
-__version__ = "$Id: background_handler.py,v 1.23 2007/03/09 14:17:15 digitalxero Exp $"
+__version__ = "$Id: background_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import thread, mimetypes, os
 from threading import Lock
--- a/orpg/mapper/background_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: background_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: background_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: background_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: background_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
--- a/orpg/mapper/base.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: base.py,v 1.18 2007/02/12 02:29:08 digitalxero Exp $
+#   $Id: base.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: base.py,v 1.18 2007/02/12 02:29:08 digitalxero Exp $"
+__version__ = "$Id: base.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from images import ImageHandler
 from orpg.tools.rgbhex import *
--- a/orpg/mapper/base_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: base_handler.py,v 1.20 2007/11/04 17:32:25 digitalxero Exp $
+#   $Id: base_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: base layer handler.
 #   layer handlers are responsible for the GUI elements of the layer
 #
-__version__ = "$Id: base_handler.py,v 1.20 2007/11/04 17:32:25 digitalxero Exp $"
+__version__ = "$Id: base_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 from orpg.orpg_windows import *
@@ -42,14 +42,12 @@
         self.chat = component.get("chat")
         self.build_ctrls()
         self.build_menu()
-        #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_LEFT_DCLICK, self.on_left_dclick)
 
     def build_ctrls(self):
         self.basesizer = wx.BoxSizer(wx.HORIZONTAL)
         self.sizer = wx.BoxSizer(wx.HORIZONTAL)
         self.buttonsizer = wx.BoxSizer(wx.HORIZONTAL)
-
         self.zoom_in_button = createMaskedButton( self, 
             dir_struct["icon"]+'zoom_in.gif', "Zoom in from x1.0", wx.ID_ANY )
         self.zoom_out_button = createMaskedButton( self, 
--- a/orpg/mapper/base_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,15 +21,15 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: base_msg.py,v 1.9 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: base_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: base_msg.py,v 1.9 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: base_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 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
@@ -38,7 +38,6 @@
 
         if not hasattr(self,"tagname"):
             raise Exception, "This is a virtual class that cannot be directly instantiated.  Set self.tagname in derived class."
-
         self._props = {}
         #  This is a dictionary that holds (value,changed) 2-tuples, indexed by attribute
         #  Avoid manipulating these values directly.  Instead, use the provided accessor methods.
@@ -217,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
     #########################################
--- a/orpg/mapper/fog.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/fog.py	Sat Jun 12 03:50:37 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
--- a/orpg/mapper/fog_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/fog_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,13 +21,13 @@
 # Author: Mark Tarrabain
 # Maintainer:
 # Version:
-#   $Id: fog_msg.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: fog_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-__version__ = "$Id: fog_msg.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: fog_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 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 ] )
+                point.set( "x", p[ 0 ] )
+                point.set( "y", p[ 1 ] )
                 elem.appendChild( point )
-        str = elem.toxml()
-        elem.unlink()
-        return str
+        return tostring(elem)
 
     # convenience method to use if only this line is modified
     #   outputs a <map/> 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 = "<fog"
+        s = "<fog>"
         if fog_string:
-            s += ">"
             s += fog_string
-            s += "</fog>"
-        else: s+="/>"
+        s += "</fog>"
         return s
 
     def interpret_dom(self,xml_dom):
         self.use_fog=1
-        #print 'fog_msg.interpret_dom called'
-        children = xml_dom._get_childNodes()
-        #print "children",children
+        children = xml_dom.getchildren()
         for l in children:
-            action = l.getAttribute("action")
-            outline = l.getAttribute("outline")
-            #print "action/outline",action, outline
+            action = l.get("action")
+            outline = l.get("outline")
             if (outline=="all"):
                 polyline=[]
                 self.fogregion.Clear()
@@ -109,14 +102,13 @@
                 self.fogregion.Clear()
             else:
                 polyline=[]
-                list = l._get_childNodes()
+                list = l.getchildren()
                 for node in list:
-                    polyline.append( IPoint().make( int(node.getAttribute("x")), int(node.getAttribute("y")) ) )
+                    polyline.append( IPoint().make( int(node.get("x")), int(node.get("y")) ) )
                     # pointarray = outline.split(";")
                     # for m in range(len(pointarray)):
                     #     pt=pointarray[m].split(",")
                     #     polyline.append(IPoint().make(int(pt[0]),int(pt[1])))
-                    #print "length of polyline", len(polyline)
             if (len(polyline)>2):
                 if action=="del": self.fogregion.FromPolygon(polyline,0)
                 else: self.fogregion.FromPolygon(polyline,1)
--- a/orpg/mapper/grid.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid.py,v 1.29 2007/12/07 20:39:49 digitalxero Exp $
+#   $Id: grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: grid.py,v 1.29 2007/12/07 20:39:49 digitalxero Exp $"
+__version__ = "$Id: grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 from isometric import *
@@ -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))
+
--- a/orpg/mapper/grid_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -20,11 +20,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid_handler.py,v 1.20 2007/04/03 00:14:35 digitalxero Exp $
+#   $Id: grid_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: grid layer handler
 #
-__version__ = "$Id: grid_handler.py,v 1.20 2007/04/03 00:14:35 digitalxero Exp $"
+__version__ = "$Id: grid_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from grid import *
 from base_handler import *
@@ -40,10 +40,11 @@
         self.grid_snap = wx.CheckBox(self, wx.ID_ANY, " Snap")
         self.grid_size = wx.TextCtrl(self, wx.ID_ANY, size=(32,-1) )
         self.grid_ratio = wx.TextCtrl(self, wx.ID_ANY, size=(32,-1) )
-        self.color_button = wx.Button(self, wx.ID_ANY, "Color", style=wx.BU_EXACTFIT)
+        self.color_button = createMaskedButton(self, dir_struct["icon"]+'grid.png', 
+                                                    'Grid Color', wx.ID_ANY, '#bdbdbd', 
+                                                    wx.BITMAP_TYPE_PNG)
         self.apply_button = wx.Button(self, wx.ID_OK, "Apply", style=wx.BU_EXACTFIT)
         self.color_button.SetBackgroundColour(wx.BLACK)
-        self.color_button.SetForegroundColour(wx.WHITE)
         self.sizer.Add(wx.StaticText(self, -1, "Size: "), 0, wx.ALIGN_CENTER)
         self.sizer.Add(self.grid_size, 0, wx.ALIGN_CENTER)
         self.sizer.Add((6,0))
--- a/orpg/mapper/grid_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: grid_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: grid_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: grid_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import map_element_msg_base
 #from base_msg import * ## ?? import all? Deprecated!?
--- a/orpg/mapper/images.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/images.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $
+#   $Id: images.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
--- a/orpg/mapper/map.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $
+#   $Id: map.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $"
+__version__ = "$Id: map.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from map_version import MAP_VERSION
 from map_msg import *
@@ -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
@@ -156,7 +158,8 @@
             else: pass
         if not ImageHandler.Queue.empty():
             (path, image_type, imageId) = ImageHandler.Queue.get()
-            if path == 'failed': img = wx.Image(dir_struct["icon"] + "failed.png", wx.BITMAP_TYPE_PNG)
+            if (path == 'failed' or path == dir_struct["icon"] + "failed.png"): 
+                img = wx.Image(dir_struct["icon"] + "failed.png", wx.BITMAP_TYPE_PNG)
             else: img = wx.ImageFromMime(path[1], path[2])
             try:
                 # Now, apply the image to the proper object
@@ -250,27 +253,44 @@
         topleft1 = self.GetViewStart()
         topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]]
         if (clientsize[0] > 1) and (clientsize[1] > 1):
-            self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
-            dc = wx.AutoBufferedPaintDC(self)
+            dc = wx.MemoryDC()
+            bmp = wx.EmptyBitmap(clientsize[0]+1, clientsize[1]+1)
+            dc.SelectObject(bmp)
             dc.SetPen(wx.TRANSPARENT_PEN)
             dc.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
             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
+            wdc = self.preppaint()
+            wdc.DrawBitmap(bmp, topleft[0], topleft[1])
             if settings.get_setting("AlwaysShowMapScale") == "1":
-                self.showmapscale(dc)
+                self.showmapscale(wdc)
         try: evt.Skip()
         except: pass
 
+    def preppaint(self):
+        dc = wx.PaintDC(self)
+        self.PrepareDC(dc)
+        return (dc)
+
     def showmapscale(self, dc):
         scalestring = "Scale x" + `self.layers['grid'].mapscale`[:3]
         (textWidth, textHeight) = dc.GetTextExtent(scalestring)
@@ -367,8 +387,6 @@
             dc.SetUserScale(self.layers['grid'].mapscale,self.layers['grid'].mapscale)
             # Grab the current map position
             pos = self.snapMarker( evt.GetLogicalPosition( dc ) )
-            # Enable brush optimizations
-            # dc.SetOptimization( True )
             # Set up the pen used for drawing our marker
             dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) )
             # Now, based on the marker mode, draw the right thing
@@ -386,8 +404,6 @@
                 # As long as we are in marker mode, we ned to update the stop point
                 self.markerStop = pos
             dc.SetPen(wx.NullPen)
-            # Disable brush optimizations
-            #dc.SetOptimization( False )
             del dc
 
     def on_tape_down(self, evt):
@@ -403,8 +419,6 @@
         self.markerMode = MARKER_MODE_MEASURE
         # Erase the old line if her have one
         if self.markerStart.x != -1 and self.markerStart.y != -1:
-            # Enable brush optimizations
-            #dc.SetOptimization( True )
             # Set up the pen used for drawing our marker
             dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) )
             # Set the DC function that we need
@@ -416,8 +430,6 @@
             # Restore the default DC function and pen
             dc.SetLogicalFunction(wx.COPY)
             dc.SetPen(wx.NullPen)
-            # Disable brush optimizations
-            #dc.SetOptimization( False )
         # Save our current start and reset the stop value
         self.markerStart = pos
         self.markerStop = pos
@@ -617,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)
@@ -638,33 +651,33 @@
                     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):
+        debug(('Developers note. Deprecated call to re_ids_in_xml!!'), parents=True)
         new_xml = ""
         tmp_map = map_msg()
         xml_dom = parseXml(str(xml))
@@ -709,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)
--- a/orpg/mapper/map_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -20,11 +20,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: map_handler.py,v 1.14 2007/04/03 00:14:35 digitalxero Exp $
+#   $Id: map_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: map layer handler
 #
-__version__ = "$Id: map_handler.py,v 1.14 2007/04/03 00:14:35 digitalxero Exp $"
+__version__ = "$Id: map_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 
--- a/orpg/mapper/map_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,13 +21,12 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map_msg.py,v 1.16 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: map_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map_msg.py,v 1.16 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: map_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-#from base import *
 from base_msg import *
 from background_msg import *
 from grid_msg import *
@@ -54,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)
@@ -85,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)
--- a/orpg/mapper/map_prop_dialog.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_prop_dialog.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map_prop_dialog.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: map_prop_dialog.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map_prop_dialog.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: map_prop_dialog.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_windows import *
 from background import *
--- a/orpg/mapper/min_dialogs.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/min_dialogs.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: min_dialogs.py,v 1.27 2006/11/13 02:23:16 digitalxero Exp $
+#   $Id: min_dialogs.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
@@ -146,10 +146,8 @@
              #############
                 min_xml = sel_rmin.toxml(action="new")
                 node_begin = "<nodehandler module='map_miniature_nodehandler' class='map_miniature_handler' name='"
-
                 if sel_rmin.label: node_begin += sel_rmin.label + "'"
                 else: node_begin += "Unnamed Miniature'"
-
                 node_begin += ">"
                 gametree = component.get('tree')
                 node_xml = node_begin + min_xml + '</nodehandler>'
@@ -308,14 +306,11 @@
         positionbox.Add(poschoicebox,0,0)
         listsizer.Add(positionbox,0, 0)
         self.listsizer = listsizer
-        #self.outline = wx.StaticBox(self,-1,"Miniature list properties")
-        #listsizer.Add(self.outline,0, wx.EXPAND)
         self.SetSizer(listsizer)
         self.SetAutoLayout(True)
         self.Fit()
         self.Bind(wx.EVT_SPINCTRL, self.on_spin, id=POS_SPIN)
         self.Bind(wx.EVT_TEXT, self.on_combo_box, id=POS_COMB)
-        #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
         self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
         self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
@@ -500,12 +495,10 @@
 
 class min_edit_dialog(wx.Dialog):
     def __init__(self,parent,min):
-        #520,265
         wx.Dialog.__init__(self,parent,-1,"Miniature",wx.DefaultPosition,wx.Size(520,350))
         (w,h) = self.GetClientSizeTuple()
         mastersizer = wx.BoxSizer(wx.VERTICAL)
         editor = min_edit_panel(self,min)
-        #editor.SetDimensions(0,0,w,h-25)
         self.editor = editor
         mastersizer.Add(editor, 1, wx.EXPAND)
         mastersizer.Add(wx.Size(10,10))
@@ -513,7 +506,6 @@
         sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
         sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        #sizer.SetDimension(0,h-25,w,25)
         mastersizer.Add(sizer, 0, wx.EXPAND)
         self.SetSizer(mastersizer)
         self.SetAutoLayout(True)
@@ -523,3 +515,4 @@
     def on_ok(self,evt):
         self.editor.update_min()
         self.EndModal(wx.ID_OK)
+
--- a/orpg/mapper/miniatures.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
+#   $Id: miniatures.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
+__version__ = "$Id: miniatures.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 import thread, time, urllib, os.path, mimetypes
@@ -196,7 +196,6 @@
             self.right = self.bmp.GetWidth()
             self.top = 0
             self.bottom = self.bmp.GetHeight()
-        
             # Draw the facing marker if needed
             if self.face != 0:
                 x_mid = self.pos.x + (self.bmp.GetWidth()/2)
@@ -206,7 +205,6 @@
                 dc.SetPen(wx.WHITE_PEN)
                 dc.SetBrush(wx.RED_BRUSH)
                 triangle = []
-        
                 # Figure out which direction to draw the marker!!
                 tri_list = {
                 FACE_WEST: [cmpPoint(self.pos.x, self.pos.y), cmpPoint(self.pos.x-5, y_mid), cmpPoint(self.pos.x, y_bottom)], 
@@ -225,7 +223,6 @@
                 dc.DrawPolygon(triangle)
                 dc.SetBrush(wx.NullBrush)
                 dc.SetPen(wx.NullPen)
-        
             # Draw the heading if needed
             if self.heading:
                 x_adjust = 0
@@ -343,31 +340,31 @@
         xml_str += " />"
         if (action == "update" and self.isUpdated) or action == "new":
             self.isUpdated = False
-            print xml_str; return xml_str
+            return xml_str
         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
@@ -376,7 +373,7 @@
     def __init__(self, canvas):
         self.canvas = canvas
         layer_base.__init__(self)
-        self.id = -1 #added.
+        self.id = -1 
         self.miniatures = []
         self.serial_number = 0
         self.show_labels = True
@@ -492,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()
--- a/orpg/mapper/miniatures_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: miniatures_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $
+#   $Id: miniatures_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Miniature layer handler
 #
-__version__ = "$Id: miniatures_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $"
+__version__ = "$Id: miniatures_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 from min_dialogs import *
@@ -36,7 +36,6 @@
 from grid import GRID_ISOMETRIC
 
 from orpg.tools.orpg_settings import settings
-
 from xml.etree.ElementTree import ElementTree, Element
 from xml.etree.ElementTree import fromstring, tostring
 
@@ -118,7 +117,6 @@
         dt = myFileDropTarget(self)
         self.canvas.SetDropTarget(dt)
         self.tooltip = wx.ToolTip('')
-        #wxInitAllImageHandlers()
 
     def build_ctrls(self):
         base_layer_handler.build_ctrls(self)
--- a/orpg/mapper/miniatures_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: miniatures_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: miniatures_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: miniatures_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: miniatures_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
@@ -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
--- a/orpg/mapper/region.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/region.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,9 +21,9 @@
 # Author: Mark Tarrabain
 # Maintainer:
 # Version:
-#   $Id: region.py,v 1.10 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: region.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-__version__ = "$Id: region.py,v 1.10 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: region.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import sys
 
--- a/orpg/mapper/whiteboard.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: whiteboard.py,v 1.47 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: whiteboard.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: whiteboard.py,v 1.47 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: whiteboard.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 from orpg.mapper.map_utils import *
@@ -119,21 +119,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 +231,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
@@ -416,13 +416,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 +436,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 +454,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)
--- a/orpg/mapper/whiteboard_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard_handler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: whiteboard_handler.py,v 1.37 2007/03/09 14:11:56 digitalxero Exp $
+#   $Id: whiteboard_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Whiteboard layer handler
 #
-__version__ = "$Id: whiteboard_handler.py,v 1.37 2007/03/09 14:11:56 digitalxero Exp $"
+__version__ = "$Id: whiteboard_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 from math import floor, sqrt
@@ -57,14 +57,16 @@
 
     def build_ctrls(self):
         base_layer_handler.build_ctrls(self)
-        self.color_button = wx.Button(self, wx.ID_ANY, "Pen Color", style=wx.BU_EXACTFIT)
+        self.color_button = createMaskedButton(self, dir_struct["icon"]+'draw.png', 
+                                                    'Pen Color', wx.ID_ANY, '#bdbdbd', 
+                                                    wx.BITMAP_TYPE_PNG)
         self.color_button.SetBackgroundColour(wx.BLACK)
         self.color_button.SetForegroundColour(wx.WHITE)
         self.drawmode_ctrl = wx.Choice(self, wx.ID_ANY, choices = ["Freeform", "Polyline","Text", "Cone", "Circle"])
         self.drawmode_ctrl.SetSelection(0) #always start showing "Freeform"
         self.radius = wx.TextCtrl(self, wx.ID_ANY, size=(32,-1) )
         self.radius.SetValue("15")
-        self.live_refresh = wx.CheckBox(self, wx.ID_ANY, " Live Refresh")
+        self.live_refresh = wx.CheckBox(self, wx.ID_ANY, " Dynamic")
         self.live_refresh.SetValue(True)
         self.widthList= wx.Choice(self, wx.ID_ANY, size= wx.Size(40, 20), 
                                         choices=['1','2','3','4','5','6','7','8','9','10'])
@@ -78,7 +80,7 @@
         self.sizer.Add(self.radius, 0, wx.EXPAND|wx.ALL, 2)
         self.sizer.Add(wx.Size(10,25))
         self.sizer.Add(self.live_refresh, 0, wx.EXPAND)
-        self.sizer.Add(wx.Size(20,25))
+        self.sizer.Add(wx.Size(10,25))
         self.sizer.Add(self.color_button, 0, wx.EXPAND)
         self.sizer.Add(wx.Size(20,25))
         self.Bind(wx.EVT_MOTION, self.on_motion)
@@ -754,9 +756,9 @@
         pos = self.get_snapped_to_logical_pos(evt)
         size = self.canvas.layers['grid'].unit_size #60
         radius = int(int(self.radius.GetValue())/5)
-        center = wx.Point(pos.x, pos.y+size*radius)
+        center = wx.Point(pos.x, pos.y)
         curve  = self.calculate_circle(center, radius, size)
-        if(self.temp_circle):
+        if self.temp_circle:
             self.canvas.layers['whiteboard'].del_temp_line(self.temp_circle)
             self.selected = None
         self.temp_circle = self.canvas.layers['whiteboard'].add_temp_line(curve)
--- a/orpg/mapper/whiteboard_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard_msg.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: whiteboard_msg.py,v 1.12 2007/03/09 14:11:56 digitalxero Exp $
+#   $Id: whiteboard_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: whiteboard_msg.py,v 1.12 2007/03/09 14:11:56 digitalxero Exp $"
+__version__ = "$Id: whiteboard_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
@@ -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
--- a/orpg/networking/gsclient.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/gsclient.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,13 +21,13 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: gsclient.py,v 1.53 2007/10/25 21:49:34 digitalxero Exp $
+#   $Id: gsclient.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the game server browser
 #
 
 from __future__ import with_statement
-__version__ = "$Id: gsclient.py,v 1.53 2007/10/25 21:49:34 digitalxero Exp $"
+__version__ = "$Id: gsclient.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import meta_server_lib
 import orpg.tools.rgbhex
@@ -269,7 +269,6 @@
         address = self.svrList[item].addy
         port = self.svrList[item].port
         self.server_list.SetItemImage(item, 1)
-
         for server in self.bookmarks.findall('server'):
             if server.get('name') == name:
                 self.bookmarks_menu.Remove(
@@ -298,8 +297,8 @@
         except: pass
         address = self.texts["address"].GetValue()
         if self.session.is_connected():
-            if self.session.host_server == address : return #currently connected to address. Do nothing.
-            else: self.frame.kill_mplay_session() #address differs, disconnect.
+            if self.session.host_server == address : return 
+            else: self.frame.kill_mplay_session()
         self.do_connect(address)
 
     def on_room_dbclick(self, evt=None):
@@ -307,13 +306,11 @@
         try: self.on_select(evt)
         except: pass
         group_id = str(self.room_list.GetItemData(self.cur_room_index))
-
         if self.NoGroups:
             self.NoGroups = False
             self.session.group_id = group_id
             self.on_server_dbclick()
             return
-
         if self.cur_room_index >= 0:
             if self.cur_room_index != 0: self.set_lobbybutton(1);
             else: self.set_lobbybutton(0);
@@ -345,7 +342,6 @@
     def on_text(self, evt):
         id = evt.GetId()
         if (id == self.texts["address"].GetValue()) and (self.cur_server_index >= 0):
-            #print "ADDRESS id = ", id, "index = ", self.cur_server_index
             self.cur_server_index = -1
         evt.Skip()
 
@@ -526,17 +522,13 @@
                 self.texts["address"].SetValue("127.0.0.1:6774")
                 self.serverNameSet = 1
             else: pass
-            #  Allow xml_dom to be collected
         except Exception, e:
             print "Server List not available."
             traceback.print_exc()
-
-                
+            
     def failed_connection(self):
         if(self.cur_server_index >= 0):
             server_index = self.servers[self.cur_server_index]
-            #  post_failed_connection will return a non-zero if the server
-            #  was removed.  If it was, refresh the display
             if(meta_server_lib.post_failed_connection(server_index.get('id'), 
                 meta=server_index.get('meta'), address=server_index.get('address'),
                 port=server_index.get('port'))):
@@ -613,11 +605,9 @@
             msg = "%s is creating room \'%s.\'" % (self.session.name, name)
             self.session.send(msg)
             self.session.send_create_group(name, pwd, boot_pwd, minversion)
-            self.set_lobbybutton(1); #enable the Lobby quickbutton
+            self.set_lobbybutton(1); 
 
     def on_size(self, evt):
-        # set column widths for room list
-        # set column widths for server list
         pass
 
     def colorize_group_list(self, groups):
--- a/orpg/networking/meta_server_lib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/meta_server_lib.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,14 +22,14 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $
+#   $Id: meta_server_lib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: A collection of functions to communicate with the meta server.
 #
 
 
 #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 $"
 
@@ -39,22 +39,18 @@
 from orpg.dirpath import dir_struct
 
 import urllib, time, sys, traceback, re
-#import orpg.minidom
 
 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:
@@ -63,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('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE)
@@ -79,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,
@@ -92,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'))
 
@@ -113,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')
@@ -167,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
 
@@ -218,121 +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("""
+        <metaservers>
+            <meta url="http://orpgmeta.appspot.com" versions="1 2" />
+            <meta url="http://traipsemeta.madmathlabs.info" versions="1 2" />
+        </metaservers>"""
+        )
     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://www.openrpg.com/openrpg_servers.php"
-    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")
-        # 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
@@ -397,7 +283,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):
@@ -470,16 +356,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
@@ -510,11 +398,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; print 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,
@@ -524,38 +415,40 @@
                                         "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,
                                         "server_data[version]":PROTOCOL_VERSION,
                                         "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:
-                if META_DEBUG: print "Problem talking to server.  Setting interval for retry ..."
-                if META_DEBUG: print data
-                if META_DEBUG: print
-                self.interval = 0
-                """
-                  If we are in the registerThread thread, then setting interval to 0
-                  will end up causing a retry in about 6 seconds (see self.run())
-                  If we are in the main thread, then setting interval to 0 will do one
-                  of two things:
-                  1)  Do the same as if we were in the registerThread
-                  2)  Cause the next, normally scheduled register() call to use the values
-                      provided in this call.
-                
-                  Which case occurs depends on where the registerThread thread is when
-                  the main thread calls register().
-                """
-                return 0  # indicates that it was okay to call, not that no errors occurred
+            for path in getMetaServerList():
+                try: # this POSTS the request and returns the result
+                    etreeEl = get_server_dom(data, path.get('url'))
+                except Exception, e:
+                    if META_DEBUG: print "Problem talking to server.  Setting interval for retry ..."
+                    if META_DEBUG: print data
+                    if META_DEBUG: print e
+                    self.interval = 0
+                    """
+                      If we are in the registerThread thread, then setting interval to 0
+                      will end up causing a retry in about 6 seconds (see self.run())
+                      If we are in the main thread, then setting interval to 0 will do one
+                      of two things:
+                      1)  Do the same as if we were in the registerThread
+                      2)  Cause the next, normally scheduled register() call to use the values
+                          provided in this call.
+                    
+                      Which case occurs depends on where the registerThread thread is when
+                      the main thread calls register().
+                    """
+                    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 tostring(etreeEl)
+                if etreeEl.get("errmsg") != None:
                     print "Error durring registration:  " + etreeEl.get("errmsg")
                     if META_DEBUG: print data
                     if META_DEBUG: print
@@ -581,11 +474,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
--- a/orpg/networking/mplay_client.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_client.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,16 +21,14 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: mplay_client.py,v 1.71 2007/05/12 20:41:54 digitalxero Exp $
+#   $Id: mplay_client.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the client stubs of the multiplayer
 # features in the orpg project.
 #
 
-__version__ = "$Id: mplay_client.py,v 1.71 2007/05/12 20:41:54 digitalxero Exp $"
+__version__ = "$Id: mplay_client.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-### Alpha ### 
-##import orpg.minidom ## Deprecated. xml.parseXml calls minidom.parseString so it was superfluous and wasteful.
 import socket, Queue, thread, traceback, errno, os, time
 
 from threading import Event, Lock
@@ -40,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
 
@@ -83,6 +81,7 @@
 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()
@@ -123,7 +122,7 @@
         self.ROLE_LURKER = "Lurker"
         ## --TaS
         try: self.ip = socket.gethostbyname(socket.gethostname())
-	except: self.ip = socket.gethostbyname('localhost')
+        except: self.ip = socket.gethostbyname('localhost')
         self.remote_ip = None
         self.version = VERSION
         self.protocol_version = PROTOCOL_VERSION
@@ -389,7 +388,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']
@@ -625,7 +623,6 @@
         el.set('from', self.id)
         el.set('pwd', pwd)
         el.set('group_id', str(group_id))
-
         self.outbox.put(tostring(el))
 
     def poll(self, evt=None):
@@ -766,7 +763,6 @@
             self.on_player_event(mplay_event(PLAYER_DEL, self.players[id]))
             if self.players.has_key(id): del self.players[id]
             if id == self.id: self.do_disconnect()
-        #  the next two cases handle the events that are used to let you know when others are typing
         elif act == "update":
             if id == self.id:
                 self.players[id] = player
@@ -842,7 +838,7 @@
         outgoing = self.toxml('del')
         if iselement(outgoing): outgoing = tostring(outgoing)
         self.outbox.put(outgoing)
-        ## Client Side Disconect Forced -- Snowdog 10-09-2003
+        ## Client Side Disconnect Forced -- Snowdog 10-09-2003
         #pause to allow GUI events time to sync.
         time.sleep(1)
         self.do_disconnect()
@@ -862,3 +858,4 @@
         self.unique_cookie += 1
         return_str = self.id + "-" + str(self.unique_cookie)
         return return_str
+
--- a/orpg/networking/mplay_messaging.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_messaging.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,24 +21,20 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: mplay_messaging.py,v 1.5 2007/05/06 16:42:59 digitalxero Exp $
+#   $Id: mplay_messaging.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the client / server messaging
 #
 
-__version__ = "$Id: mplay_messaging.py,v 1.5 2007/05/06 16:42:59 digitalxero Exp $"
+__version__ = "$Id: mplay_messaging.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-import socket
-import Queue
-import thread
-import traceback
+import socket, Queue, thread, traceback, os, time
+
 from threading import Event, Lock
 from xml.sax.saxutils import escape
 from struct import pack, unpack, calcsize
 from string import *
 from orpg.orpg_version import VERSION, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
-import os
-import time
 
 from orpg.tools.orpg_log import logger
 from orpg.orpgCore import component
@@ -91,20 +87,6 @@
         self.players = {}
         self.groups = {}
 
-        #Setup Stuff from the Server
-        """
-        if kwargs.has_key('inbox'): self.inbox = kwargs['inbox']
-        if kwargs.has_key('sock'): self.sock = kwargs['sock']
-        if kwargs.has_key('ip'): self.ip = kwargs['ip']
-        if kwargs.has_key('role'): self.role = kwargs['role']
-        if kwargs.has_key('id'): self.id = kwargs['id']
-        if kwargs.has_key('group_id'): self.group_id = kwargs['group_id']
-        if kwargs.has_key('name'): self.name = kwargs['name']
-        if kwargs.has_key('version'): self.version = kwargs['version']
-        if kwargs.has_key('protocol_version'): self.protocol_version = kwargs['protocol_version']
-        if kwargs.has_key('client_string'): self.client_string = kwargs['client_string']
-        """
-
         ### Alpha ###
         self.inbox = kwargs['inbox'] or pass
         self.sock = kwargs['sock'] or pass
@@ -207,7 +189,6 @@
     def __str__(self):
         return "%s(%s)\nIP:%s\ngroup_id:%s\n%s (%s)" % (self.name, self.id, self.ip, self.group_id, self.idle_time(), self.connected_time())
 
-    # idle time functions added by snowdog 3/31/04
     def update_idle_time(self):
         self.lastmessagetime = time.time()
 
@@ -326,7 +307,6 @@
         #Message Action thread expires and closes here.
         return
 
-    #Privet functions
     def sendThread( self, arg ):
         "Sending thread.  This thread reads from the data queue and writes to the socket."
         # Wait to be told it's okay to start running
@@ -352,11 +332,7 @@
     def sendMsg( self, sock, msg ):
         """Very simple function that will properly encode and send a message to te
         remote on the specified socket."""
-
-        # Calculate our message length
         length = len( msg )
-
-        # Encode the message length into network byte order
         lp = pack( 'i', socket.htonl( length ) )
 
         try:
@@ -434,13 +410,11 @@
         msgData = ""
         try:
             lenData = self.recvData( sock, self.lensize )
-
             # Now, convert to a usable form
             (length,) = unpack( 'i', lenData )
             length = socket.ntohl( length )
             # Read exactly the remaining amount of data
             msgData = self.recvData( sock, length )
-
             if self.isServer: logger.debug("('data_recv', " + str(length+4) + ")")
         except: logger.exception("Exception: messenger->recvMsg():\n" + traceback.format_exc())
         return msgData
@@ -448,3 +422,4 @@
 if __name__ == "__main__":
     test = messenger(None)
     print test.build_message('hello', "This is a test message", attrib1="hello world", attrib2="hello world2", attrib3="hello world3")
+
--- a/orpg/networking/mplay_server.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_server.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,7 +22,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: mplay_server.py,v 1.155 2008/01/24 03:52:03 digitalxero Exp $
+#   $Id: mplay_server.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the server of the multiplayer
 # features in the orpg project.
@@ -33,7 +33,7 @@
 
 from __future__ import with_statement
 
-__version__ = "$Id: mplay_server.py,v 1.155 2008/01/24 03:52:03 digitalxero Exp $"
+__version__ = "$Id: mplay_server.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 #!/usr/bin/env python
 """
@@ -64,7 +64,7 @@
 from orpg.tools.decorators import debugging
 
 # Snag the version number
-from orpg.orpg_version import VERSION, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
+from orpg.orpg_version import VERSION, DISTRO, DIS_VER, BUILD, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
 
 #Plugins
 from server_plugins import ServerPlugins
@@ -253,7 +253,7 @@
         self.allowRemoteKill = False
         self.allowRemoteAdmin = True
         self.sendLobbySound = False
-        self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu' ##used?
+        #self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu' ##used?
 
     def initServer(self, **kwargs):
         for atter, value in kwargs.iteritems(): setattr(self, atter, value)
@@ -325,6 +325,7 @@
             self.saveBanList()
         except Exception, e:
             self.log_msg("Exception in initBanList() " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     # This method writes out the server's ban list added by Darren
     def saveBanList( self ):
@@ -343,6 +344,7 @@
             file.close()
         except Exception, e:
             self.log_msg("Exception in saveBanList() " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     # This method reads in the server's configuration file and reconfigs the server
     # as needed, over-riding any default values as requested.
@@ -526,6 +528,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg("Exception in initServerConfig() " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def makePersistentRooms(self):
         'Creates rooms on the server as defined in the server config file.'
@@ -571,6 +574,7 @@
             return pr
         except:
             self.log_msg("Exception occured in isPersistentRoom(self,id)")
+            self.log_msg( ('exception', str(e)) )
             return 0
 
     #-----------------------------------------------------
@@ -612,7 +616,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
@@ -644,21 +648,22 @@
 
     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
         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)
+            while serverId == '0':
+                serverId, cookie = self.metas[meta].getIdAndCookie()
+            if serverId != '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)
@@ -668,11 +673,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.
@@ -682,7 +686,6 @@
         #  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 + ": ")
@@ -695,7 +698,7 @@
 
         #  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():
+            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)
@@ -775,8 +778,8 @@
             try:
                 sentl = sock.send( lp ) # Send the encoded length
                 sentm = sock.send( msg ) # Now, send the message the the length was describing
-            except socket.error, e: self.log_msg( e )
-            except Exception, e: self.log_msg( e )
+            except socket.error, e: self.log_msg( ('exception', str(e)) ); self.log_msg( e )
+            except Exception, e: self.log_msg( e ); self.log_msg( ('exception', str(e)) )
 
 
     def recvData( self, sock, readSize ):
@@ -818,7 +821,7 @@
             try:
                 if useCompression and cmpType != None: msgData = cmpType.decompress(msgData)
             except: traceback.print_exc()
-        except Exception, e: self.log_msg( "Exception: recvMsg(): " + str(e) )
+        except Exception, e: self.log_msg( "Exception: recvMsg(): " + str(e) ); self.log_msg( ('exception', str(e)) )
         return msgData
 
     def kill_server(self):
@@ -886,8 +889,14 @@
         print "'help' or '?' or 'h' - for this help message"
         print
 
-    def broadcast(self,msg):
-        self.send_to_all("0","<msg to='all' from='0' group_id='1'><font color='#FF0000'>" + msg + "</font></msg>")
+    def broadcast(self, msg):
+        broadcast = '<chat type="1" version="1.0"><font color="#FF0000">' +msg+ '</font></chat>'
+        chat = Element('chat')
+        chat.set('type', '1')
+        chat.set('version', '1.0')
+        chat.text = broadcast
+        msg = self.buildMsg('all', '0', '1', tostring(chat))
+        self.send_to_all('0', msg)
 
     def console_log(self):
         if self.log_to_console == 1:
@@ -910,6 +919,7 @@
             print
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
         self.p_lock.release()
 
     """
@@ -996,6 +1006,7 @@
             print
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
         self.p_lock.release()
 
     """
@@ -1028,6 +1039,7 @@
             print "\nStatistics: groups: " + str(len(self.groups)) + "  players: " +  str(len(self.players))
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
         self.p_lock.release()
 
 
@@ -1045,6 +1057,7 @@
                         print "Bad Player Ref (#" + id + ") in group"
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
         self.p_lock.release()
 
     def update_request(self,newsock, xml_dom):
@@ -1069,7 +1082,7 @@
             msg = self.groups[group_id].game_map.get_all_xml()
             self.send(msg,id,group_id)
 
-    def new_request(self,newsock, xml_dom, LOBBY_ID='0'):
+    def new_request(self, newsock, xml_dom, LOBBY_ID='0'):
         #build client stub
         props = {}
         # Don't trust what the client tells us...trust what they connected as!
@@ -1101,22 +1114,24 @@
 
         # send confirmation
         data = self.recvMsg(newsock, new_stub.useCompression, new_stub.compressionType)
-        try: xml_dom = XML(data)
+        try: 
+            xml_dom = XML(data)
         except Exception, e:
             print e
             (remote_host,remote_port) = newsock.getpeername()
             bad_xml_string =  "Your client sent an illegal message to the server and will be disconnected. "
             bad_xml_string += "Please report this bug to the development team at:<br /> "
-            bad_xml_string += "<a href=\"http://sourceforge.net/tracker/?group_id=2237&atid=102237\">OpenRPG bugs "
-            bad_xml_string += "(http://sourceforge.net/tracker/?group_id=2237&atid=102237)</a><br />"
-            self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='" + props['id'] + "' group_id='0' />" + bad_xml_string, 
-                            new_stub.useCompression, new_stub.compressionType)
+            bad_xml_string += "<a href='http://www.assembla.com/spaces/traipse_dev/tickets/'>Traipse-Dev "
+            bad_xml_string += "(http://www.assembla.com/spaces/traipse_dev/tickets/)</a><br />"
+            msg = self.buildMsg(props['id'], props['id'], '0', bad_xml_string)
+            self.sendMsg( newsock, msg, new_stub.useCompression, new_stub.compressionType)
 
             time.sleep(2)
             newsock.close()
             print "Error in parse found from " + str(remote_host) + ".  Disconnected."
             print "  Offending data(" + str(len(data)) + "bytes)=" + data
             print "Exception=" + str(e)
+            self.log_msg( ('exception', str(e)) )
             #if xml_dom: xml_dom.unlink()
             return
 
@@ -1195,11 +1210,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()
 
@@ -1214,7 +1227,7 @@
             newsock.close()
 
         #  Display the lobby message
-        self.SendLobbyMessage(newsock,props['id'])
+        self.SendLobbyMessage(newsock, props['id'])
 
     def checkClientVersion(self, clientversion):
         minv = self.minClientVersion.split('.')
@@ -1234,8 +1247,9 @@
         #  prepend this server's version string to the the lobby message
         """
         try:
-            lobbyMsg = "You have connected to an <a href=\"http://www.openrpg.com\">OpenRPG</a> "
-            lobbyMsg += "server, version '" + VERSION + "'"
+            lobbyMsg = "You have connected to a <a href='http://www.knowledgearcana.com/traipse-openrpg'>"
+            lobbyMsg += DISTRO +'</a> '+ DIS_VER +' {'+ BUILD+'}'
+            lobbyMsg += " server, built on OpenRPG version '" + VERSION + "'"
 
             # See if we have a server name to report!
             if len(self.serverName): lobbyMsg += ", named '" + self.serverName + "'."
@@ -1250,7 +1264,6 @@
                 open_msg = open( self.userPath + "LobbyMessage.html", "r" )
                 lobbyMsg += open_msg.read()
                 open_msg.close()
-
             # Send the server's lobby message to the client no matter what
             self.sendMsg(socket, "<msg to='" + player_id + "' from='0' group_id='0' />" + lobbyMsg, 
                         self.players[player_id].useCompression, self.players[player_id].compressionType)
@@ -1275,6 +1288,7 @@
 
         except Exception, e:
             self.log_msg(("Error binding request socket!", e))
+            self.log_msg( ('exception', str(e)) )
             self.alive = 0
 
         while self.alive:
@@ -1291,9 +1305,10 @@
                 """
                 thread.start_new_thread(self.acceptedNewConnectionThread, ( newsock, addr ))
 
-            except:
+            except Exception, e:
                 print "The following exception caught accepting new connection:"
                 traceback.print_exc()
+                self.log_msg( ('exception', str(e)) )
 
         #  At this point, we're done and cleaning up.
         self.log_msg("server socket listening thread exiting...")
@@ -1314,6 +1329,7 @@
             try: newsock.close()
             except Exception, e:
                 self.log_msg( str(e) )
+                self.log_msg( ('exception', str(e)) )
                 print str(e)
             return #returning causes connection thread instance to terminate
         if data == "<system/>":
@@ -1335,10 +1351,11 @@
 
         except:
             try: newsock.close()
-            except: pass
+            except Exception, e: pass
             self.log_msg( "Error in parse found from " + str(addr) + ".  Disconnected.")
             self.log_msg("  Offending data(" + str(len(data)) + "bytes)=" + data)
             self.log_msg( "Exception:")
+            self.log_msg( ('exception', str(e)) )
             traceback.print_exc()
             return #returning causes connection thread instance to terminate
 
@@ -1356,6 +1373,7 @@
             print "The following  message: " + str(data)
             print "from " + str(addr) + " created the following exception: "
             traceback.print_exc()
+            self.log_msg( ('exception', str(e)) )
             return #returning causes connection thread instance to terminate
 
     """
@@ -1390,26 +1408,33 @@
                 data = None
             except Exception, e:
                 self.log_msg(str(e))
+                self.log_msg( ('exception', str(e)) )
         self.log_msg("message handler thread exiting...")
         self.incoming_event.set()
 
     def parse_incoming_dom(self, data):
-        end = data.find(">") #locate end of first element of message
+        end = data.find(">")
         head = data[:end+1]
-        xml_dom = None
+        msg = data[end+1:]
+        ### This if statement should help close invalid messages. ###
+        if head[end:] != '/':
+            if head[end:] != '>': head = head[:end] + '/>'
         try:
-            xml_dom = XML(head)
+            try: xml_dom = fromstring(head)
+            except: xml_dom = fromstring(head[:end] +'/>')
             self.message_action(xml_dom, data)
-
         except Exception, e:
             print "Error in parse of inbound message. Ignoring message."
             print "  Offending data(" + str(len(data)) + "bytes)=" + data
             print "Exception=" + str(e)
+            self.log_msg( ('exception', str(e)) )
         
     def message_action(self, xml_dom, data):
         tag_name = xml_dom.tag
         if self.svrcmds.has_key(tag_name): self.svrcmds[tag_name]['function'](xml_dom, data)
-        else: raise Exception, "Not a valid header!"
+        else: 
+            raise Exception, "Not a valid header!"
+            self.log_msg( ('exception', 'Not a valid header!') )
         #Message Action thread expires and closes here.
         return
 
@@ -1513,6 +1538,7 @@
                 print "Bad input: " + data
         except Exception,e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def join_group(self, xml_dom, data):
         try:
@@ -1546,6 +1572,7 @@
             self.move_player(from_id, group_id)
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
 
     """
     # move_player function -- added by Snowdog 4/03
@@ -1563,6 +1590,7 @@
                 else: self.players[from_id].role = "Lurker"
             except Exception, e:
                 print "exception in move_player() "
+                self.log_msg( ('exception', str(e)) )
                 traceback.print_exc()
 
             old_group_id = self.players[from_id].change_group(group_id, self.groups)
@@ -1591,6 +1619,7 @@
                 except Exception, e:
                     roomMsg = ""
                     self.log_msg(str(e))
+                    self.log_msg( ('exception', str(e)) )
 
                 # Spit that darn message out now!
                 self.players[from_id].outbox.put("<msg to='" + from_id + "' from='0' group_id='" + group_id + "' />" + roomMsg)
@@ -1603,10 +1632,12 @@
             #notify user about others in the room
             self.return_room_roles(from_id,group_id)
             self.log_msg(("join_group", (self.groups[group_id].name, group_id, from_id)))
+            self.log_msg(("update_group", (self.groups[old_group_id].name, old_group_id, len(self.groups[old_group_id].players) )))
             self.log_msg(("update_group", (self.groups[group_id].name, group_id, len(self.groups[group_id].players) )))
             self.handle_role("set", from_id, self.players[from_id].role, self.groups[group_id].boot_pwd, group_id)
         except Exception, e:
             self.log_msg(str(e))
+            self.log_msg( ('exception', str(e)) )
         thread.start_new_thread(self.registerRooms,(0,))
 
     def return_room_roles(self, from_id, group_id):
@@ -1632,7 +1663,7 @@
         if persist !=0: ins="Persistant "
         lmsg = "Creating " + ins + "Group... (" + str(group_id) + ") " + str(name)
         self.log_msg( lmsg )
-        self.log_msg(("create_group", (str(name), int(group_id), pwd, 0) ))
+        self.log_msg(("create_group", (str(name), int(group_id), 0, 'No' if pwd == '' else 'Yes') ))
 
     def change_group_name(self, gid, name, pid):
         "Change the name of a group"
@@ -1765,7 +1796,7 @@
             else: self.send_to_all("0",self.groups[group_id].toxml('update'))
             #The register Rooms thread
             thread.start_new_thread(self.registerRooms,(0,))
-        except Exception, e: self.log_msg(str(e))
+        except Exception, e: self.log_msg( ('exception', str(e)) )
 
     def del_player(self, id, group_id):
         try:
@@ -1775,15 +1806,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()
-        except Exception, e: self.log_msg(str(e))
+            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()))
 
     def incoming_player_handler(self, xml_dom, data):
@@ -1798,7 +1824,7 @@
             try:
                 self.send_player_list(id,group_id)
                 self.send_group_list(id)
-            except Exception, e: traceback.print_exc()
+            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)
@@ -1840,8 +1866,11 @@
         to_id = xml_dom.get("to")
         from_id = xml_dom.get("from")
         group_id = xml_dom.get("group_id")
+        ## Backwards compatibility with older clients
         end = data.find(">")
         msg = data[end+1:]
+        if msg[-6:] == '</msg>': msg = msg[:-6]
+        data = msg
 
         if from_id == "0" or len(from_id) == 0:
             print "WARNING!! Message received with an invalid from_id.  Message dropped."
@@ -1865,21 +1894,27 @@
                 self.players[from_id].self_message('The lobby map may not be altered.')
             elif to_id.lower() == 'all':
                 #valid map for all players that is not the lobby.
-                self.send_to_group(from_id,group_id,data)
+                msg = self.buildMsg('all', from_id, group_id, data)
+                self.send_to_group(from_id,group_id,msg)
                 self.groups[group_id].game_map.init_from_xml(msg)
             else:
                 #attempting to send map to specific individuals which is not supported.
                 self.players[from_id].self_message('Invalid map message. Message not sent to others.')
 
         elif msg[:6] == '<boot ':
+            msg = self.buildMsg('all', from_id, group_id, data)
             self.handle_boot(from_id,to_id,group_id,msg)
 
         else:
             if to_id == 'all':
                 if self.groups[group_id].moderated and not self.groups[group_id].voice.has_key(from_id):
                     self.players[from_id].self_message('This room is moderated - message not sent to others')
-                else: self.send_to_group(from_id,group_id,data)
-            else: self.players[to_id].outbox.put(data)
+                else: 
+                    msg = self.buildMsg('all', from_id, group_id, data)
+                    self.send_to_group(from_id,group_id,msg)
+            else: 
+                msg = self.buildMsg('all', from_id, group_id, data)
+                self.players[to_id].outbox.put(msg)
         self.check_group_members(group_id)
         return
 
@@ -1937,6 +1972,7 @@
                 print "due to the following exception:"
                 traceback.print_exc()
                 print "Ignoring boot message"
+                self.log_msg( ('exception', str(e)) )
 
     def handle_boot(self,from_id,to_id,group_id,msg):
         xml_dom = None
@@ -1946,10 +1982,11 @@
                 xml_dom = XML(msg)
                 given_boot_pwd = xml_dom.get("boot_pwd")
 
-            except:
+            except Exception, e:
                 print "Error in parse of boot message, Ignoring."
                 print "Exception: "
                 traceback.print_exc()
+                self.log_msg( ('exception', str(e)) )
 
             try:
                 actual_boot_pwd = self.groups[group_id].boot_pwd
@@ -2002,6 +2039,7 @@
             except Exception, e:
                 traceback.print_exc()
                 self.log_msg('Exception in handle_boot() ' + str(e))
+                self.log_msg( ('exception', str(e)) )
 
         finally:
             try:
@@ -2009,6 +2047,7 @@
             except Exception, e:
                 traceback.print_exc()
                 self.log_msg('Exception in xml_dom.unlink() ' + str(e))
+                self.log_msg( ('exception', str(e)) )
 
     """
     # admin_kick function -- by Snowdog 4/03
@@ -2039,6 +2078,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg('Exception in admin_kick() ' + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     ### Alpha ### Addition added to assist in Un Banning users.
     def admin_build_banlist(self):
@@ -2065,6 +2105,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg('Exception in admin_banip() ' + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def admin_ban(self, id, message="", silent = 0):
         "Ban a player from a server from the console"
@@ -2078,7 +2119,8 @@
             self.saveBanList()
 
             # Send a message to everyone in the victim's room, letting them know someone has been booted
-            ban_msg = "<msg to='all' from='0' group_id='%s'/><font color='#FF0000'>Banning '(%s) %s' from server... %s</font>" % ( group_id, id, self.players[id].name, str(message))
+            msg = 'Banning ('+id+') '+self.players[id].name+' from server... </font>'
+            msg = self.buildMsg('all', '0', group_id, msg)
             self.log_msg("ban_msg:" + ban_msg)
             if (silent == 0): self.send_to_group("0", group_id, ban_msg)
             time.sleep( .1 )
@@ -2096,6 +2138,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg('Exception in admin_ban() ' + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def admin_unban(self, ip):
         self.admin_build_banlist()
@@ -2106,6 +2149,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg('Exception in admin_unban() ' + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def admin_banlist(self):
         msg = []
@@ -2145,7 +2189,6 @@
         except: pass
 
     def send(self,msg,player,group):
-        debug(msg)
         self.players[player].send(msg,player,group)
 
     def send_to_all(self,from_id,data):
@@ -2158,11 +2201,11 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg("Exception: send_to_all(): " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def send_to_group(self, from_id, group_id, data):
         #data = ("<msg to='all' from='0' group_id='"+str(group_id)+"' /><font color='#FF0000'>" + data + "</font>")
         data = ServerPlugins.postParseIncoming(data) #Function breaks here.
-        debug(data)
         try:
             self.p_lock.acquire()
             keys = self.groups[group_id].get_player_ids()
@@ -2172,6 +2215,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg("Exception: send_to_group(): " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def send_player_list(self,to_id,group_id):
         try:
@@ -2183,17 +2227,17 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg("Exception: send_player_list(): " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     def send_group_list(self, to_id, action="new"):
         try:
-            print self.groups
             for key in self.groups:
                 xml = self.groups[key].toxml(action)
-                print xml, key
                 self.players[to_id].outbox.put(xml)
         except Exception, e:
             self.log_msg("Exception: send_group_list(): (client #"+to_id+") : " + str(e))
             traceback.print_exc()
+            self.log_msg( ('exception', str(e)) )
 
     """
     # KICK_ALL_CLIENTS()
@@ -2211,6 +2255,7 @@
         except Exception, e:
             traceback.print_exc()
             self.log_msg("Exception: kick_all_clients(): " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
     """
     # This really has little value as it will only catch people that are hung
@@ -2236,7 +2281,12 @@
                         self.admin_kick(k,"Removing dead client", self.silent_auto_kick)
         except Exception, e:
             self.log_msg("Exception: check_group_members(): " + str(e))
+            self.log_msg( ('exception', str(e)) )
 
+    def buildMsg(self, toId, fromId, roomId, data):
+        msg = '<msg to="' +toId+ '" from="' +fromId+ '" group_id="' +roomId+ '">'
+        msg += data+ '</msg>'
+        return msg
 
     def remote_admin_handler(self,xml_dom,data):
         """
@@ -2285,106 +2335,112 @@
             #determine action to take based on command (cmd)
             if cmd == "list":
                 #return player list to this user.
-                msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.player_list_remote()
+                msg = self.buildMsg(pid, '0', gid, self.player_list_remote())
                 self.players[pid].outbox.put(msg)
             elif cmd == "banip":
                 ip = xml_dom.get("bip")
                 name = xml_dom.get("bname")
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Banned: " + str(ip)
+                msg = self.buildMsg(pid, '0', gid, str(ip))
                 self.admin_banip(ip, name)
             elif cmd == "ban":
                 id = xml_dom.get("bid")
-                msg = "<msg to='" + id + "' from='0' group_id='" + gid + "'> Banned!"
+                msg = self.buildMsg(id, '0', gid, 'Banned!')
                 self.players[pid].outbox.put(msg)
                 self.admin_ban(id, "")
             ### Alpha ### and untested
             elif cmd == "boot":
                 id = xml_dom.get("bid")
-                msg = "<msg to='" + id + "' from='0' group_id='" + gid + "'> Booted!"
+                msg = self.buildMsg(id, '0', gid, 'Booted!!')
                 self.players[pid].outbox.put(msg)
                 self.admin_kick(id, "")
             #############
             elif cmd == "unban":
                 ip = xml_dom.get("ip")
                 self.admin_unban(ip)
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Unbaned: " + str(ip)
+                msg = self.buildMsg(pid, '0', gid, str(ip))
                 self.players[pid].outbox.put(msg)
             elif cmd == "banlist":
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.admin_banlist()
+                msg = self.buildMsg(pid, '0', gid, self.admin_banlist())
                 self.players[pid].outbox.put(msg)
             elif cmd == "killgroup":
                 ugid = xml_dom.get("gid")
                 if ugid == "0":
-                    m = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
-                    m += "Cannot Remove Lobby! Remote administrator request denied!"
-                    self.players[pid].outbox.put(m)
+                    m + "Cannot Remove Lobby! Remote administrator request denied!"
+                    msg = self.buildMsg(pid, '0', gid, m)
+                    self.players[pid].outbox.put(msg)
                 else:
                     result = self.prune_room(ugid)
-                    msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + str(result)
+                    msg = self.buildMsg(pid, '0', gid, str(result))
                     self.players[pid].outbox.put(msg)
 
             elif cmd == "message":
                 tuid = xml_dom.get("to_id")
                 msg = xml_dom.get("msg")
-                pmsg = "<msg to='" + tuid + "' from='0' group_id='" + self.players[tuid].group_id + "' >" + msg
+                pmsg = self.buildMsg(tuid, '0', self.players[tuid].group_id, msg)
                 try: self.players[tuid].outbox.put(pmsg)
                 except:
-                    msg = "<msg to='" + pid + "' from='0' group_id='" + gid + ">Unknown Player ID: No message sent."
+                    msg = "Unknown Player ID: No message sent."
+                    msg = self.buildMsg(pid, '0', gid, msg)
                     self.players[pid].outbox.put(msg)
             elif cmd == "broadcast":
                 bmsg = xml_dom.get("msg")
-                self.broadcast(bmsg)
+                self.send_to_all('0', bmsg)
             elif cmd == "killserver" and self.allowRemoteKill:
                 #dangerous command..once server stopped it must be restarted manually
                 self.kill_server()
             elif cmd == "uptime":
-                msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.uptime(1)
+                msg = self.uptime(1)
+                msg = self.buildMsg(pid, '0', gid, msg)
                 self.players[pid].outbox.put(msg)
             elif cmd == "help":
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
-                msg += self.AdminHelpMessage()
+                msg = self.AdminHelpMessage()
+                msg = self.buildMsg(pid, '0', gid, msg)
                 self.players[pid].outbox.put( msg)
             elif cmd == "roompasswords":
                 # Toggle if room passwords are allowed on this server
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
-                msg += self.RoomPasswords()
+                msg = self.RoomPasswords()
+                msg = self.buildMsg(pid, '0', gid, msg)
                 self.players[pid].outbox.put( msg)
             elif cmd == "createroom":
                 rm_name = xml_dom.get("name")
                 rm_pass = xml_dom.get("pass")
                 rm_boot = xml_dom.get("boot")
                 result = self.create_temporary_persistant_room(rm_name, rm_boot, rm_pass)
-                msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + result
+                msg = self.buildMsg(pid, '0', gid, result)
                 self.players[pid].outbox.put(msg)
             elif cmd == "nameroom":
                 rm_id   = xml_dom.get("rmid")
                 rm_name = xml_dom.get("name")
                 result = self.change_group_name(rm_id,rm_name,pid)
-                msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'/>" + result
+                msg = self.buildMsg(pid, '0', gid, result)
                 self.players[pid].outbox.put(msg)
             elif cmd == "passwd":
                 tgid = xml_dom.get("gid")
                 npwd = xml_dom.get("pass")
                 if tgid == "0":
-                    msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
-                    msg += "Server password may not be changed remotely!"
+                    msg = "Server password may not be changed remotely!"
+                    msg = self.buildMsg(pid, '0', gid, msg)
                     self.players[pid].outbox.put(msg)
                 else:
                     try:
                         self.groups[tgid].boot_pwd = npwd
-                        msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Password changed for room " + tgid
+                        msg = "Password changed for room " + tgid
+                        msg = self.buildMsg(pid, '0', gid, msg)
                         self.players[pid].outbox.put(msg)
                     except: pass
             elif cmd == "savemaps":
                 for g in self.groups.itervalues(): g.save_map()
-                msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Persistent room maps saved"
+                msg = "Persistent room maps saved"
+                msg = self.buildMsg(pid, '0', gid, msg)
                 self.players[pid].outbox.put(msg)
             else:
-                msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'><i>[Unknown Remote Administration Command]</i>"
+                msg = "<i>[Unknown Remote Administration Command]</i>"
+                msg = self.buildMsg(pid, '0', gid, msg)
                 self.players[pid].outbox.put(msg)
         except Exception, e:
             self.log_msg("Exception: Remote Admin Handler Error: " + str(e))
             traceback.print_exc()
+            self.log_msg( ('exception', str(e)) )
 
     def toggleRemoteKill(self):
         if self.allowRemoteKill: self.allowRemoteKill = False
@@ -2552,8 +2608,8 @@
             pl += "<tr><td colspan='4' bgcolor=" + COLOR1 + ">"
             pl += "<font color=" + COLOR4 + "><b><i>Statistics: groups: " + str(len(self.groups)) + "  "
             pl += "players: " +  str(len(self.players)) + "</i></b></font></td></tr></table>"
-        except Exception, e: self.log_msg(str(e))
+        except Exception, e: self.log_msg(str(e)); self.log_msg( ('exception', str(e)) )
         self.p_lock.release()
         return pl
 
-server = mplay_server()
+server = mplay_server()     
--- a/orpg/networking/mplay_server_gui.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_server_gui.py	Sat Jun 12 03:50:37 2010 -0500
@@ -6,24 +6,22 @@
 
 __appname__=' OpenRPG GUI Server v0.7 '
 __version__='$Revision: 1.26 $'[11:-2]
-__cvsinfo__='$Id: mplay_server_gui.py,v 1.26 2007/11/06 00:32:39 digitalxero Exp $'[5:-2]
+__cvsinfo__="$Id: mplay_server_gui.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"[5:-2]
 __doc__="""OpenRPG Server Graphical Interface"""
 
-import os, sys, time, types
+import os, sys, time, types, webbrowser
 
 from orpg.dirpath import dir_struct
 from orpg.tools.validate import validate
 from orpg.orpg_wx import *
 from threading import Thread
 
-import webbrowser
-
 from meta_server_lib import post_server_data, remove_server
 from mplay_server import mplay_server, server
 
 from xml.dom import minidom
 from orpg.orpgCore import component
-from orpg.tools.orpg_log import debug
+from orpg.tools.orpg_log import debug, DebugConsole
 from orpg.tools.orpg_settings import settings
 
 from xml.etree.ElementTree import ElementTree, Element, iselement
@@ -32,11 +30,7 @@
 # Constants ######################################
 SERVER_RUNNING = 1
 SERVER_STOPPED = 0
-
-### Alpha ###
 MENU_MODIFY_BANLIST = wx.NewId()
-#############
-
 MENU_PLAYER_CREATE_ROOM = wx.NewId()
 
 # Our new event type that gets posted from one
@@ -157,8 +151,8 @@
         (room, room_id, players, passworded) = data
         i = self.InsertStringItem(0, str(room_id))
         self.SetStringItem(i, 1, room)
-        self.SetStringItem(i, 2, players)
-        self.SetStringItem(i, 3, str(passworded))
+        self.SetStringItem(i, 2, str(players))
+        self.SetStringItem(i, 3, passworded)
 
     def DeleteGroup(self, data):
         i = self.FindItem(-1, str(data))
@@ -168,7 +162,7 @@
         (room, room_id, players) = data
         i = self.FindItem( -1, str(room_id))
         self.SetStringItem( i, 1, room )
-        if players: self.SetStringItem(i, 2, str(players))
+        self.SetStringItem(i, 2, str(players))
         ### Need to add room for Password Updates ###
 
 class Connections(wx.ListCtrl):
@@ -268,7 +262,6 @@
             self.SetItem(item)
 
     def update(self, player):
-        #try: int(player); i = self.FindItemData( -1, int(player) )
         i = self.FindItemData( -1, int(player["id"]) )
         if i > -1:
             self.SetStringItem(i, 1, self.stripHtml(player["name"]))
@@ -328,7 +321,7 @@
                 BanMsg = wx.TextEntryDialog( self, "Enter A Message To Send:",
                                                  "Ban Message", message, wx.OK|wx.CANCEL|wx.CENTRE )
                 if BanMsg.ShowModal() == wx.ID_OK: message = BanMsg.GetValue()
-                else: message = ''
+                else: return
                 Silent = wx.MessageDialog(None, 'Silent Ban?', 'Question', 
                     wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                 if Silent.ShowModal() == wx.ID_YES: silent = 1
@@ -337,14 +330,30 @@
                 self.remove( playerID )
             elif menuItem == 4:
                 msg = self.GetMessageInput( "Send a message to player" )
-                if len(msg): self.main.server.server.send( msg, playerID, str(groupID) )
+
+                broadcast = '<chat type="1" version="1.0"><font color="#FF0000">' +msg+ '</font></chat>'
+                chat = Element('chat')
+                chat.set('type', '1')
+                chat.set('version', '1.0')
+                chat.text = broadcast
+                msg = self.main.server.server.buildMsg(str(playerID), '0', '1', msg)
+
+                if len(msg): self.main.server.server.players[playerID].outbox.put(msg)
             #Leave this in for now.
             elif menuItem == 5:
                 msg = self.GetMessageInput( "Send message to room of this player")
+
+                broadcast = '<chat type="1" version="1.0"><font color="#FF0000">' +msg+ '</font></chat>'
+                chat = Element('chat')
+                chat.set('type', '1')
+                chat.set('version', '1.0')
+                chat.text = broadcast
+                msg = self.main.server.server.buildMsg('all', '0', '1', tostring(chat))
+
                 if len(msg): self.main.server.server.send_to_group('0', str(groupID), msg )
             elif menuItem == 6:
                 msg = self.GetMessageInput( "Broadcast Server Message" )
-                if len(msg): self.main.server.server.broadcast( msg )
+                if len(msg): self.main.server.server.broadcast(msg )
             elif menuItem == 3:
                 version_string = self.main.server.server.obtain_by_id(playerID, 'client_string')
                 if version_string: wx.MessageBox("Running client version " + version_string,"Version")
@@ -361,8 +370,8 @@
     STATUS = SERVER_STOPPED
     def __init__(self, parent, id, title):
         wx.Frame.__init__(self, parent, id, title, size = (760, 560) )
-        if wx.Platform == '__WXMSW__': icon = wx.Icon( dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO )
-        else: icon = wx.Icon( dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF )
+        if wx.Platform == '__WXMSW__': icon = wx.Icon(dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO)
+        else: icon = wx.Icon(dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF)
         self.SetIcon(icon)
         self.serverName = "Server Name"
         self.bootPwd = ""
@@ -391,6 +400,7 @@
         cb["delete_group"] = self.OnDeleteGroup
         cb["join_group"] = self.OnJoinGroup
         cb['update_group'] = self.OnUpdateGroup
+        cb['exception'] = self.OnException
         cb["role"] = self.OnSetRole
         self.callbacks = cb
 
@@ -408,10 +418,10 @@
 
         # File Menu
         menu = wx.Menu()
-        menu.Append( 1, 'Start', 'Start server.')
-        menu.Append( 2, 'Stop', 'Shutdown server.')
+        menu.Append(1, 'Start', 'Start server.')
+        menu.Append(2, 'Stop', 'Shutdown server.')
         menu.AppendSeparator()
-        menu.Append( 3, 'E&xit', 'Exit application.')
+        menu.Append(3, 'E&xit', 'Exit application.')
         self.Bind(wx.EVT_MENU, self.OnStart, id=1)
         self.Bind(wx.EVT_MENU, self.OnStop, id=2)
         self.Bind(wx.EVT_MENU, self.OnExit, id=3)
@@ -419,23 +429,24 @@
 
         # Registration Menu
         menu = wx.Menu()
-        menu.Append( 4, 'Register', 'Register with OpenRPG server directory.')
-        menu.Append( 5, 'Unregister', 'Unregister from OpenRPG server directory.')
+        menu.Append(4, 'Register', 'Register with OpenRPG server directory.')
+        menu.Append(5, 'Unregister', 'Unregister from OpenRPG server directory.')
         self.Bind(wx.EVT_MENU, self.OnRegister, id=4)
         self.Bind(wx.EVT_MENU, self.OnUnregister, id=5)
         self.mainMenu.Append( menu, '&Registration' )
 
         # Server Configuration Menu
         menu = wx.Menu()
-        menu.Append( 6, 'Ban List', 'Modify Ban List.')
+        menu.Append(6, 'Ban List', 'Modify Ban List.')
         menu.Append(11, 'Zombies', 'Set auto-kick time for zombie clients')
         menu.Append(14, 'Send Size', 'Adjust the send size limit')
         menu.AppendSeparator()
-        menu.Append( 7, 'Start Ping', 'Ping players to validate remote connection.' )
-        menu.Append( 8, 'Stop Ping', 'Stop validating player connections.' )
-        menu.Append( 9, 'Ping Interval', 'Change the ping interval.' )
+        menu.Append(7, 'Start Ping', 'Ping players to validate remote connection.' )
+        menu.Append(8, 'Stop Ping', 'Stop validating player connections.' )
+        menu.Append(9, 'Ping Interval', 'Change the ping interval.' )
         menu.AppendSeparator()
-        menu.AppendCheckItem( 10, 'Server Logging', 'Turn on or off the Server GUI Log').Check(self.do_log)
+        menu.AppendCheckItem(10, 'Server Logging', 
+                                'Turn on or off the Server GUI Log').Check(self.do_log)
         menu.AppendCheckItem(12, 'Room Passwords', 'Allow or Deny Room Passwords').Check(False)
         menu.AppendCheckItem(13, 'Remote Admin', 'Allow or Deny Remote Admin').Check(False)
         menu.AppendCheckItem(15, 'Remote Kill', 'Allow or Deny Remote Admin Server Kill').Check(False)
@@ -444,37 +455,82 @@
         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.mainMenu.Append( menu, '&Configuration' )
-        self.SetMenuBar( self.mainMenu )
+        self.mainMenu.Append( menu, '&Configuration')
+
+        # Traipse Suite of Additions.
+        self.traipseSuite = wx.Menu()
+        self.debugger = DebugConsole(self)
+        self.mainMenu.Insert(3, self.traipseSuite, "&Traipse Suite")
 
-        self.mainMenu.Enable( 2, False )
-        self.mainMenu.Enable( 4, False )
-        self.mainMenu.Enable( 5, False )
+        #Debugger Console
+        self.debugConsole = wx.MenuItem(self.traipseSuite, -1, "Debug Console", "Debug Console")
+        self.Bind(wx.EVT_MENU, self.OnMB_DebugConsole, self.debugConsole)
+        self.traipseSuite.AppendItem(self.debugConsole)
+
+        self.SetMenuBar(self.mainMenu)
+
+        self.mainMenu.Enable(2, False)
+        self.mainMenu.Enable(4, False)
+        self.mainMenu.Enable(5, False)
 
         # Disable the ping menu items
-        self.mainMenu.Enable( 7, False )
-        self.mainMenu.Enable( 8, False )
-        self.mainMenu.Enable( 9, False )
+        self.mainMenu.Enable(7, False)
+        self.mainMenu.Enable(8, False)
+        self.mainMenu.Enable(9, False)
 
         # Disable placeholders
-        self.mainMenu.Enable( 11, False )
-        self.mainMenu.Enable( 14, False )
-        self.mainMenu.Enable( 12, False )
-        self.mainMenu.Enable( 13, False )
-        self.mainMenu.Enable( 15, False )
+        self.mainMenu.Enable(11, False)
+        self.mainMenu.Enable(14, False)
+        self.mainMenu.Enable(12, False)
+        self.mainMenu.Enable(13, False)
+        self.mainMenu.Enable(15, False)
+
+    def OnException(self, error):
+        self.TraipseSuiteWarn('debug')
+        self.debugger.console.AppendText(".. " + str(error) +'\n')
+
+    def OnMB_DebugConsole(self, evt):
+        self.TraipseSuiteWarnCleanup('debug')
+        if self.debugger.IsShown() == True: self.debugger.Hide()
+        else: self.debugger.Show()
+
+    def TraipseSuiteWarn(self, menuitem):
+        ### Allows for the reuse of the 'Attention' menu.
+        ### component.get('frame').TraipseSuiteWarn('item') ### Portable
+        self.mainMenu.Remove(3)
+        self.mainMenu.Insert(3, self.traipseSuite, "&Traipse Suite!")
+        if menuitem == 'debug':
+            if self.debugger.IsShown() == True:
+                self.mainMenu.Remove(3)
+                self.mainMenu.Insert(3, self.traipseSuite, "&Traipse Suite")
+            else:
+                self.debugConsole.SetBitmap(wx.Bitmap(dir_struct["icon"] + 'spotlight.png'))
+                self.traipseSuite.RemoveItem(self.debugConsole)
+                self.traipseSuite.AppendItem(self.debugConsole)
+
+    def TraipseSuiteWarnCleanup(self, menuitem):
+        ### Allows for portable cleanup of the 'Attention' menu.
+        ### component.get('frame').TraipseSuiteWarnCleanup('item') ### Portable
+        self.mainMenu.Remove(3)
+        self.mainMenu.Insert(3, self.traipseSuite, "&Traipse Suite")        
+        if menuitem == 'debug':
+            self.traipseSuite.RemoveItem(self.debugConsole)
+            self.debugConsole.SetBitmap(wx.Bitmap(dir_struct["icon"] + 'clear.gif'))
+            self.traipseSuite.AppendItem(self.debugConsole)
+
     def build_body(self):
         """ Create the ViewNotebook and logger. """
         splitter = wx.SplitterWindow(self, -1, style=wx.NO_3D | wx.SP_3D)
-        nb = wx.Notebook( splitter, -1 )
+        nb = wx.Notebook(splitter, -1)
         self.conns = Connections(nb, self)
         self.groups = Groups(nb, self)
-        self.msgWindow = HTMLMessageWindow( nb )
+        self.msgWindow = HTMLMessageWindow(nb)
         nb.AddPage(self.conns, "Players")
         nb.AddPage(self.groups, 'Rooms')
-        nb.AddPage( self.msgWindow, "Messages" )
+        nb.AddPage(self.msgWindow, "Messages")
 
         log = wx.TextCtrl(splitter, -1, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
-        wx.Log.SetActiveTarget( wx.LogTextCtrl(log) )
+        wx.Log.SetActiveTarget(wx.LogTextCtrl(log))
         splitter.SplitHorizontally(nb, log, 400)
         splitter.SetMinimumPaneSize(40)
         self.nb = nb
@@ -529,12 +585,14 @@
     def OnDataSent(self, bytes):
         self.total_messages_sent += 1
         self.total_data_sent += bytes
-        self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), self.total_messages_sent), 1)
+        self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), 
+                                self.total_messages_sent), 1)
 
     def OnDataRecv(self, bytes):
         self.total_messages_received += 1
         self.total_data_received += bytes
-        self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), self.total_messages_received), 2)
+        self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), 
+                                self.total_messages_received), 2)
 
     def OnCreateGroup( self, data ):
         (room, room_id, player, pwd) = data
@@ -563,28 +621,29 @@
     def OnStart(self, event = None):
         """ Start server. """
         if self.STATUS == SERVER_STOPPED:
-            # see if we already have name specified 
+            ## Set name and admin password as empty
+            self.serverName = ''
+            self.bootPwd = ''
+            # see if we already have serverName and bootPwd specified
             try:
                 validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
                 configDoc = parse(dir_struct["user"] + 'server_ini.xml').getroot()
-                if configDoc.get("name"): self.serverName = configDoc.get("name")
+                self.serverName = configDoc.get("name")
+                if configDoc.get("admin"): self.bootPwd = configDoc.get("admin") 
+                elif configDoc.get("boot"): self.bootPwd = configDoc.get("boot") 
             except: pass 
             if self.serverName == '':
                 self.serverName = 'Server Name'
-                serverNameEntry = wx.TextEntryDialog(self, "Please Enter The Server Name You Wish To Use:",
-                                                 "Server's Name", self.serverName, wx.OK|wx.CANCEL|wx.CENTRE )
+                serverNameEntry = wx.TextEntryDialog(self, 
+                                    "Please Enter The Server Name You Wish To Use:",
+                                    "Server's Name", 
+                                    self.serverName, wx.OK|wx.CANCEL|wx.CENTRE)
                 if serverNameEntry.ShowModal() == wx.ID_OK: self.serverName = serverNameEntry.GetValue()
-            # see if we already have password specified 
-            try: 
-                validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
-                configDoc = parse(dir_struct["user"] + 'server_ini.xml').getroot()
-                if configDoc.get("admin"): self.bootPwd = configDoc.get("admin") 
-                elif configDoc.get("boot"): self.bootPwd = configDoc.get("boot") 
-            except: pass 
             if self.bootPwd == '': 
                 serverPasswordEntry = wx.TextEntryDialog(self, 
-                                            "Please Enter The Server Admin Password:", "Server's Password", 
-                                            self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE)
+                                    "Please Enter The Server Admin Password:", 
+                                    "Server's Password", 
+                                    self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE)
                 if serverPasswordEntry.ShowModal() == wx.ID_OK: self.bootPwd = serverPasswordEntry.GetValue()
             if len(self.serverName):
                 wx.BeginBusyCursor()
@@ -593,25 +652,26 @@
                 self.STATUS = SERVER_RUNNING
                 self.sb.SetStatusText("Running", 3)
                 self.SetTitle(__appname__ + "- (running) - (unregistered)")
-                self.mainMenu.Enable( 1, False )
-                self.mainMenu.Enable( 2, True )
-                self.mainMenu.Enable( 4, True )
+                self.mainMenu.Enable(1, False)
+                self.mainMenu.Enable(2, True)
+                self.mainMenu.Enable(4, True)
                 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.
@@ -622,8 +682,8 @@
             wx.BeginBusyCursor()
             self.server.server.register(self.serverName)
             self.sb.SetStatusText( ("%s" % (self.serverName)), 4 )
-            self.mainMenu.Enable( 4, False )
-            self.mainMenu.Enable( 5, True )
+            self.mainMenu.Enable(4, False)
+            self.mainMenu.Enable(5, True)
             #self.mainMenu.Enable( 2, False )
             self.SetTitle(__appname__ + "- (running) - (registered)")
             wx.EndBusyCursor()
@@ -636,11 +696,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):
@@ -667,7 +728,7 @@
 
     def ExitConfirmed(self, event=None):
         """ Quit the program. """
-        self.OnStop()
+        self.OnStop('Quit')
         self.BanListDialog.Destroy()
         wx.CallAfter(self.Destroy)
 
--- a/orpg/orpg_version.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_version.py	Sat Jun 12 03:50:37 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"
 DIS_VER = "Ornery Orc"
-BUILD = "100115-02"
+BUILD = "100505-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/orpg_windows.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_windows.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $
+#   $Id: orpg_windows.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: orpg custom windows
 #
 
-__version__ = "$Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $"
+__version__ = "$Id: orpg_windows.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import *
@@ -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)
 
--- a/orpg/orpg_xml.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_xml.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,18 +21,17 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: orpg_xml.py,v 1.12 2007/07/19 20:33:10 digitalxero Exp $
+#   $Id: orpg_xml.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: xml utilies
 #
 
 from orpg import minidom
 import string
-
 from orpg.tools.orpg_log import logger, debug
 
 class xml:
-    debug('Deprecated call to orpg_xml!!')
+    debug(('Developers note. Deprecated call to orpg_xml!!'), parents=True)
     def __init__(self):
         pass
 
--- a/orpg/player_list.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/player_list.py	Sat Jun 12 03:50:37 2010 -0500
@@ -22,12 +22,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: player_list.py,v 1.29 2007/03/30 19:12:06 digitalxero Exp $
+#   $Id: player_list.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: This is the main entry point of the oprg application
 #
 
-__version__ = "$Id: player_list.py,v 1.29 2007/03/30 19:12:06 digitalxero Exp $"
+__version__ = "$Id: player_list.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $"
 
 from orpg.orpg_windows import *
 from orpg.dirpath import dir_struct
--- a/orpg/pluginhandler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/pluginhandler.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,5 +1,7 @@
 from orpg.orpg_wx import *
 from orpg.orpgCore import component
+from xml.etree.ElementTree import ElementTree, Element, parse
+from xml.etree.ElementTree import fromstring, tostring
 
 class PluginHandler:
     # Initialization subroutine.
@@ -82,22 +84,22 @@
         self.settings.add_setting(self.name, setting, value, options, help)
 
     def plugin_send_msg(self, to, plugin_msg):
-        xml_dom = self.xml.parseXml(plugin_msg)
-        xml_dom = xml_dom._get_documentElement()
-        xml_dom.setAttribute('from', str(self.session.id))
-        xml_dom.setAttribute('to', str(to))
-        xml_dom.setAttribute('group_id', str(self.session.group_id))
-        tag_name = xml_dom._get_tagName()
+        xml_dom = fromstring(plugin_msg)
+        #xml_dom = xml_dom.getroot()
+        xml_dom.set('from', str(self.session.id))
+        xml_dom.set('to', str(to))
+        xml_dom.set('group_id', str(self.session.group_id))
+        tag_name = xml_dom.tag
         if not tag_name in self.session.core_msg_handlers:
             xml_msg = '<plugin to="' + str(to)
             xml_msg += '" from="' + str(self.session.id)
             xml_msg += '" group_id="' + str(self.session.group_id)
-            xml_msg += '" />' + xml_dom.toxml()
+            xml_msg += '" />' + tostring(xml_dom)
             self.session.outbox.put(xml_msg)
         else:
             #Spoofing attempt
             pass
-        xml_dom.unlink()
+        #xml_dom.unlink()
 
     def message(self, text):
         return text
--- a/orpg/templates/default_LobbyMessage.html	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_LobbyMessage.html	Sat Jun 12 03:50:37 2010 -0500
@@ -1,40 +1,38 @@
 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 <html>
-  <body>
-    <table cellspacing=3 cellpadding=4 width="100%">
-      <tr>
-       <td bgcolor="#101010" align="bottom">
-         <center><a href="http://www.openrpg.com"><img src="images/splash.gif" border="0"></a></center>
-       </td>
-      </tr>
-      <tr>
-        <td bgcolor="#73A183" align="center">
-         <table cellpadding="0" cellspacing="0" width="100%">
-           <tr>
-            <td align="center" width="100%">
-             Many thanks goes to all of those who contributed!
-             <BR>
-              The developers in alphabetical order are:
-             <BR>
-            Thomas Baleno, Andrew Bennett, Lex Berezhny, Ted Berg,
-            Bernhard Bergbauer, Chris Blocher ,Ben Collins-Sussman, Robin Cook, Greg Copeland,
-            Chris Davis, Michael Edwards, Andrew Ettinger, Dj Gilcrease, Todd Faris,
-            Christopher Hickman, Paul Hosking, Scott Mackay, Brian Manning,
-            Jesse McConnell, Brian Osman, Rome Reginelli, Christopher Rouse, Dave Sanders, Mark Tarrabain,
-            David Byron, and Tyler Starke.
-            </td>
-              </tr>
-                <tr>
-                <td align="center" width="100%">
-                This product is licensed under the <a href="http://www.gnu.org">GNU</a> <a href="http://www.gnu.org/philosophy/license-list.html">GPL License.</a>
-             </td>
-             </tr>
-            </table>
-           </td>
-      </tr>
-    </table>
 
-<!-- Created: Thursday November 9 23:55:12 PDT 2003 -->
-  </body>
+<table width="100%" border="3" cellpadding="4" cellspacing="1" >
+  <tr>
+    <th bgcolor="#D4ECFB" align="left" valign="top">
+      <strong>Welcome to an OpenRPG Server</strong>
+        <br />
+        Add a message here.
+    </th>
+    <th bgcolor="#73A183" width="45%" align="left" valign="top">
+      <strong>The OpenRPG Project</strong>
+        <br />
+        Who is this force?
+    </th> </th> <!-- I have to close the header twice? That's a disability.-->
+  </tr>  
+  <tr>
+    <td border="2" bgcolor="#ECECEC" valign="top">
+    Here is an example Room Message that can be easily modified to fit the needs of your server.
+    The room message has two rows and two cells. One row is for headers, and one row is for cells.
+    The main area here can be an introduction, and the side area to the right can contain a game schedule.
+    <p>If you have created a Wiki or forums, be sure and put links to those as well.</p>
+    </td>    
+    <td border="2" bgcolor="#D5E9D7" valign="top">
+    Thomas Baleno, Andrew Bennett, Lex Berezhny, Ted Berg,
+    Bernhard Bergbauer, Chris Blocher, Ben Collins-Sussman, Robin Cook, Greg Copeland,
+    Chris Davis, Michael Edwards, Andrew Ettinger, Dj Gilcrease, Todd Faris,
+    Christopher Hickman, Paul Hosking, Scott Mackay, Brian Manning,
+    Jesse McConnell, Brian Osman, Rome Reginelli, Christopher Rouse, Dave Sanders, Mark Tarrabain,
+    David Byron, David Vrabel, and Tyler Starke.
+    <p>And of course, the Community!</p>
+    <p>Many thanks to all who contributed!</p>
+    </td>
+  </tr>
+</table>
+
 </html>
 
--- a/orpg/templates/default_Lobby_map.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_Lobby_map.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -1,7 +1,7 @@
 <nodehandler class="min_map" icon="compass" module="core" name="miniature Map">
 <map version='1.0' sizex='650' sizey='384' action='new'>
 <grid size='50'  mode='0' line='0' snap='1' color='#000000'/>
-<bg path='http://www.knowledgearcana.com/arcane-art/Traipse_Skeleton.png' type='2'/>
+<bg path='http://www.knowledgearcana.com/arcane-art/ornery-orc-small.png' type='2'/>
 <miniatures serial='2'/>
 </map>
 </nodehandler>
--- a/orpg/templates/default_settings.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_settings.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -2,10 +2,9 @@
     <tab name="General" type="tab">
         <tab name="Networking" type="grid">
             <Heartbeat options="bool" value="1" help="This sends a message to the server to keep alive your connection when idle." />
-            <MetaServerBaseURL help="This is the URL that contains the server list." options="URL" value="http://www.openrpg.com/openrpg_servers.php"/>
+            <MetaServers help="Contains a list of Meta Servers" options=".xml file" value="metaservers.xml"/>
             <ImageServerBaseURL help="This is the URL that contains the server list." options="URL" value="http://openrpg.digitalxero.net/imgupload/index.php"/>
-            <LocalImageBaseURL help="This is the URL that contains the server list." options="URL" value="http://127.0.0.1:6774/webfiles/"/>
-            <LocalorRemote help="Decide to load files locally or remotely. CherryPy must be running for local files." options="Local | Remote" value="Local"/>
+            <LocalorRemote help="Decide to load files locally or remotely. CherryPy must be running for local files." options="Local | Remote" value="Remote"/>
         </tab>
         <tab name="Sound" type="grid">
             <UnixSoundPlayer help="This is the path to the executable used by unix clients to play sounds." options="path to executable" value=""/>
--- a/orpg/templates/feature.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/feature.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -1,6 +1,159 @@
-<nodehandler class="tabber_handler" icon="help" map="" module="containers" name="Traipse OpenRPG" version="1.0">
-  <nodehandler class="tabber_handler" frame="499,524,156,129" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Quick Help" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">Quick Help:
+<nodehandler class="tabber_handler" frame="400,400,0,48" icon="help" map="" module="containers" name="Traipse OpenRPG" version="1.0">
+    <nodehandler class="tabber_handler" frame="636,449,368,80" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0">
+      <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
+        <text hide_title="0" multiline="1" raw_mode="0" send_button="0">Welcome to Traipse OpenRPG.
+
+This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
+
+What is OpenRPG:
+OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
+
+What is Traipse OpenRPG:
+Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
+
+Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.
+
+The User Manual:
+The user manual is divided into Chapters and Sections.  Each Chapter will go over the various features of OpenRPG and attempt to explain them in an easy to understand format.
+
+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.</text>
+      </nodehandler>
+      <nodehandler class="tabber_handler" icon="player" map="Traipse OpenRPG::User Manual" module="containers" name="Chat" version="1.0">
+        <nodehandler class="textctrl_handler" frame="400,400,0,47" icon="note" map="Traipse OpenRPG::User Manual::Chat" module="forms" name="Using Chat" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="0">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.</text>
+        </nodehandler>
+      </nodehandler>
+      <nodehandler class="tabber_handler" icon="ccmap" map="Traipse OpenRPG::User Manual" module="containers" name="Map" version="1.0">
+        <nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::Map" module="forms" name="Using The Map" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="0">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.
+
+Lurker or in the Lobby: 
+You cannot access any map tab or changes it's settings.
+
+Player: 
+You have access to the Miniatures tab and the Whiteboard tab.
+
+GM: 
+You have access to all of the tabs.
+
+The Layers:
+A small description of each of the layers.
+
+Background: 
+You can set an image as the background, an image as a tile, or you can set a color.
+
+Grid: 
+You can change the grid size, lines, turn off the grid snap, and change the grid shape.
+
+Miniatures: 
+You can add new or remove miniatures and change mini properties and labels.
+
+Whiteboard: 
+With the whiteboard you can draw lines or add text to the map.
+
+Fog: 
+The fog layer hides the entire map from the prying eyes of players.
+</text>
+        </nodehandler>
+      </nodehandler>
+      <nodehandler class="tabber_handler" frame="400,400,424,101" icon="gear" map="Traipse OpenRPG::User Manual" module="containers" name="Game Tree" version="1.0">
+        <nodehandler class="tabber_handler" frame="400,400,472,75" icon="labtop" map="Traipse OpenRPG::User Manual::Game Tree" module="containers" name="Namespace 2.0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Namespace 2.0" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">Namespace 2.0
+
+Internal Namespace: !=NodeName=! or !=GridName::Row,Colum=!
+External Namespace: !&amp;Container::NodeName&amp;! or !&amp;Container::GridName::Row,Colum&amp;!
+
+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.
+</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Namespace 2.0" module="forms" name="Internal" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">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 &#8220;Strength&#8221; 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=! )</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Namespace 2.0" module="forms" name="External" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">External Namespace: !&amp;Container::NodeName&amp;!
+-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 &#8216;largest&#8217; container 
+(typically the one that shows in the gametree when fully collapsed). It doesn&#8217;t matter how 
+many smaller containers within the same container it&#8217;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 !&amp;Container::NodeName&amp;! syntax for normal nodes.
+-Uses !&amp;Container::NodeName::Row,Colum&amp;! to reference cells within a grid.
+
+Examples:
+!&amp;3.5 Character Sheet::Strength&amp;!
+(Will find the node named &#8220;Strength&#8221; within the larger container &#8220;3.5 Character Sheet&#8221; and 
+insert it in place of !&amp;3.5 Character Sheet::Strength&amp;!)
+
+!&amp;3.5 Character Sheet::Ability Scores::3,5&amp;!
+(Will find the cell in Row 3, Colum 5 in within the larger container &#8220;3.5 Character Sheet&#8221; and 
+insert its contents in place of !&amp;3.5 Character Sheet::Ability Scores::3,5&amp;!)</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Namespace 2.0" module="forms" name="Other Notes" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">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: 
+!&amp;LargerContainer::SmallerContainer::NodeName&amp;!
+
+I.E.:
+The Largest container is called &#8220;Character Sheets.&#8221; It contains three other, Smaller 
+containers called &#8220;Luke,&#8221; &#8220;Leia,&#8221; and &#8220;Vader.&#8221; If you want to call the &#8220;Strength&#8221; node located 
+in &#8220;Leia&#8221; you will have to specify it like so: !&amp;Character Sheets::Leia::Strength&amp;!. </text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,392,87" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Namespace 2.0" module="forms" name="Author Notes" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="1">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.
+
+&lt;b&gt;1:&lt;/b&gt; !&amp;4e PC Sheet::Slot 1&amp;!
+&lt;b&gt;2:&lt;/b&gt; !&amp;4e PC Sheet::Belt::Slot 1&amp;!
+&lt;b&gt;3:&lt;/b&gt; !&amp;4e PC Sheet::Inventory&amp;!
+&lt;b&gt;4:&lt;/b&gt; !&amp;4e PC Sheet::Inventory::Slot 1&amp;!
+
+  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)
+</text></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,595,57" icon="note" map="Traipse OpenRPG::User Manual::Game Tree" module="forms" name="Grids" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="1">Grids can now be called from by adding a Row, Column to the end of the grid reference.
+
+Example: !&amp;Abilities::2,2&amp;!</text>
+        </nodehandler><nodehandler class="tabber_handler" frame="527,400,259,85" icon="book" map="Traipse OpenRPG::User Manual::Game Tree" module="containers" name="Ornery (past)" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)" module="containers" name="Reference Examples" version="1.0">
+          <nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="forms" name="Quick Help" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="1" send_button="0">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
 
@@ -57,130 +210,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.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Root Reference" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="forms" name="Root Reference" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
 Works at the tree level. Must be exact.
 
 &lt;b&gt;Root Reference 1:&lt;/b&gt; !@Reference Examples::Group::Child@!
-&lt;b&gt;Root Reference 2:&lt;/b&gt; !@Reference Examples::Grid::(2,1)@!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Grid Reference" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Grid Reference&lt;/b&gt;
+&lt;b&gt;Root Reference 2:&lt;/b&gt; !@Reference Examples::Grid::2,1@!</text>
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="forms" name="Grid Reference" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Grid Reference&lt;/b&gt;
 Works by looking at the (Row, Column) of a Grid.
 
-&lt;b&gt;Grid Reference 1:&lt;/b&gt; !@Reference Examples::Grid::(1,1)@!
-&lt;b&gt;Grid Reference 2:&lt;/b&gt; !!Grid::(1,1)!!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Child Reference" version="1.0">
-  <text hide_title="1" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Child Reference&lt;/b&gt;
+&lt;b&gt;Grid Reference 1:&lt;/b&gt; !@Reference Examples::Grid::1,1@!
+&lt;b&gt;Grid Reference 2:&lt;/b&gt; !!Grid::1,1!!</text>
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="forms" name="Child Reference" version="1.0">
+            <text hide_title="1" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Child Reference&lt;/b&gt;
 Works at the current tree location.
 
 &lt;b&gt;Child Reference 1:&lt;/b&gt; !!Group::Child!!
 &lt;b&gt;Child Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!
 </text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Parent Reference" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Parent Reference&lt;/b&gt;
-Works by indexing the map of the node with the Reference.
-Works with a Child Reference only. 
-
-&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Group_3::Child_3!!
-&lt;b&gt;Parent Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!</text>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples" module="containers" name="Group" version="1.0">
-  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
-</nodehandler></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="forms" name="Child" version="1.0">
-  <text multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
-</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell size="147">0</cell>
-      <cell>0</cell>
-    </row>
-    <row version="1.0">
-      <cell>!!Group::Child!!</cell>
-      <cell>0</cell>
-    </row>
-  </grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
-  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
-
-This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
-
-What is OpenRPG:
-OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
-
-What is Traipse OpenRPG:
-Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
-
-Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using Chat" version="1.0">
-  <text multiline="1" send_button="0">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.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using The Map" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">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.  
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="forms" name="Parent Reference" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Parent Reference&lt;/b&gt;
+Works by indexing the tree map of the node with the Reference. Allows you to start from a 'Parent'.
 
-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.
-
-Lurker or in the Lobby: You cannot access any map tab or changes it's settings.
-
-Player: You have access to the Miniatures tab and the Whiteboard tab.
-
-GM: You have access to all of the tabs.
-
-The Layers:
-A small description of each of the layers.
-
-Background: You can set an image as the background, an image as a tile, or you can set a color.
-
-Grid: You can change the grid size, lines, turn off the grid snap, and change the grid shape.
-
-Miniatures: You can add new or remove miniatures and change mini properties and labels.
-
-Whiteboard: With the whiteboard you can draw lines or add text to the map.
-
-Fog: The fog layer hides the entire map from the prying eyes of players.
-</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="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.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="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.
+&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Child_2!!
+&lt;b&gt;Parent Reference 2:&lt;/b&gt; !#Bonus Nodes::Deck::Draw#!</text>
+          </nodehandler>
+          <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="containers" name="Group" version="1.0">
+            <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
+              <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
+                <text hide_title="0" multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+              </nodehandler>
+              <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
+                <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
+                  <text hide_title="0" multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+                </nodehandler>
+                </nodehandler>
+              </nodehandler>
+            <nodehandler class="textctrl_handler" frame="400,134,382,175" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples::Group" module="forms" name="Child" version="1.0">
+              <text hide_title="0" multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
+            </nodehandler>
+            </nodehandler>
+          <nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
+            <grid autosize="1" border="1">
+              <row version="1.0">
+                <cell size="147">0</cell>
+                <cell>0</cell>
+              </row>
+              <row version="1.0">
+                <cell>!!Group::Child!!</cell>
+                <cell>0</cell>
+              </row>
+            </grid>
+            <macros>
+              <macro name="" />
+            </macros>
+          </nodehandler>
+        </nodehandler>
+        <nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)" module="forms" name="Node Referencing" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="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)
 
@@ -232,8 +324,46 @@
 
 Examples: 
 !@Kammen-Pai::Cast::Ray of Frost@!
-!@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Setting up a Server" version="1.0">
-  <text multiline="1" send_button="0">In Traipse starting a server has never been easier.  The setup is as easy as 1., 2., 3
+!@Kammen-Pai::Feat::Ability Focus@!</text>
+        </nodehandler>
+        <nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Ornery (past)" module="forms" name="Additions &amp; Tips" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="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.</text>
+        </nodehandler>
+        </nodehandler></nodehandler>
+      <nodehandler class="tabber_handler" icon="labtop" map="Traipse OpenRPG::User Manual" module="containers" name="The Server" version="1.0">
+        <nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::The Server" module="forms" name="Setting up a Server" version="1.0">
+          <text hide_title="0" multiline="1" raw_mode="0" send_button="0">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.
 
@@ -244,174 +374,284 @@
 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!</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Adding to the Manual" version="1.0">
-  <text multiline="1" send_button="0">Do you see something that could be explained eaiser?  Report the problem as a bug and it will be added to the manual.</text>
-</nodehandler><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Release Notes" version="1.0">
-    <link href="http://www.assembla.com/wiki/show/traipse" />
-  </nodehandler>
-  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Traipse User Guide" version="1.0">
-    <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
-  </nodehandler>
-  </nodehandler><nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
-  <nodehandler class="form_handler" frame="514,464,307,57" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
-  <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
-  <list hide_title="0" raw_mode="1" send_button="1" type="1">
-    <option caption="" selected="0" value="">!!Chapter 1::Part 1!!</option>
-    <option caption="" selected="0" value="">!!Chapter 1::Part 2!!</option>
-    <option caption="" selected="1" value="">!!Chapter 1::Part 3!!</option>
-  </list>
-</nodehandler><nodehandler class="tabber_handler" frame="400,400,392,45" icon="book" map="Traipse OpenRPG::Bonus Nodes::Book" module="containers" name="Chapter 1" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 1" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+        </nodehandler>
+      </nodehandler>
+      <nodehandler class="tabber_handler" frame="400,400,0,48" icon="browser" map="Traipse OpenRPG::User Manual" module="containers" name="Links" version="1.0">
+        <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Release Notes" version="1.0">
+          <link href="http://www.assembla.com/wiki/show/traipse" />
+        </nodehandler>
+        <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Traipse User Guide" version="1.0">
+          <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
+        </nodehandler>
+      </nodehandler>
+    </nodehandler>
+    <nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
+      <nodehandler class="form_handler" frame="514,464,307,57" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
+        <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
+          <list hide_title="0" raw_mode="1" send_button="1" type="1">
+            <option caption="" selected="0" value="">!=Chapter 1::Part 1=!</option>
+            <option caption="" selected="0" value="">!=Chapter 1::Part 2=!</option>
+            <option caption="" selected="1" value="">!=Chapter 1::Part 3=!</option>
+          </list>
+        </nodehandler>
+        <nodehandler class="tabber_handler" frame="400,400,392,45" icon="book" map="Traipse OpenRPG::Bonus Nodes::Book" module="containers" name="Chapter 1" version="1.0">
+          <nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 1" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
 &lt;b&gt;Chapter 1 Part 1&lt;/b&gt;
 &lt;br /&gt;&lt;br /&gt;
 An introduction to your adventure module can be placed here.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,435,110" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 2" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,435,110" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 2" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
 &lt;b&gt;Chapter 1 Part 2&lt;/b&gt;
 &lt;br /&gt;&lt;br /&gt;
 The adventurers have come this far.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 3" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 3" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
 &lt;b&gt;Chapter 1 Part 3&lt;/b&gt;
 &lt;br /&gt;&lt;br /&gt;
 Is this the end already?</text>
-</nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="409,414,422,76" height="600" icon="wizard1" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Deck" version="1.0" width="400">
-  <nodehandler class="rpg_grid_handler" frame="400,400,425,69" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Deck" module="rpg_grid" name="52 Card Deck" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>AS</cell>
-      <cell>AD</cell>
-    <cell>AC</cell><cell>AH</cell></row>
-    <row version="1.0">
-      <cell>KS</cell>
-      <cell>KD</cell>
-    <cell>KC</cell><cell>KH</cell></row>
-  <row version="1.0"><cell>QS</cell><cell>QD</cell><cell>QC</cell><cell>QH</cell></row><row version="1.0"><cell>JS</cell><cell>JD</cell><cell>JC</cell><cell>JH</cell></row><row version="1.0"><cell>10S</cell><cell>10D</cell><cell>10C</cell><cell>10H</cell></row><row version="1.0"><cell>9S</cell><cell>9D</cell><cell>9C</cell><cell>9H</cell></row><row version="1.0"><cell>8S</cell><cell>8D</cell><cell>8C</cell><cell>8H</cell></row><row version="1.0"><cell>7S</cell><cell>7D</cell><cell>7C</cell><cell>7H</cell></row><row version="1.0"><cell>6S</cell><cell>6D</cell><cell>6C</cell><cell>6H</cell></row><row version="1.0"><cell>5S</cell><cell>5D</cell><cell>5C</cell><cell>5H</cell></row><row version="1.0"><cell>4S</cell><cell>4D</cell><cell>4C</cell><cell>4H</cell></row><row version="1.0"><cell>3S</cell><cell>3D</cell><cell>3C</cell><cell>3H</cell></row><row version="1.0"><cell>2S</cell><cell>2D</cell><cell>2C</cell><cell>2H</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,90,497,106" icon="note" map="Traipse OpenRPG::Bonus Nodes::Deck" module="forms" name="Draw" version="1.0">
-  <text multiline="0" raw_mode="1" send_button="1">!!52 Card Deck::([#1d13], [#1d4])!!</text>
-</nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,501,72" height="600" icon="orc" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Encounters" version="1.0" width="400">
-  <nodehandler class="listbox_handler" frame="400,153,348,150" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="forms" name="Roll" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option caption="" selected="0" value="">!!Chart::([#1d3],1)!!</option>
-    <option caption="" selected="1" value="">!!Chart::([#1d2],2)!!</option>
-    </list>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,0,48" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="rpg_grid" name="Chart" version="1.0">
-  <grid autosize="0" border="1">
-    <row version="1.0">
-      <cell size="119">!!Set 1::Enc 1!!</cell>
-      <cell size="115">!!Set 2::Enc 1!!</cell></row>
-    <row version="1.0">
-      <cell>!!Set 1::Enc 2!!</cell>
-      <cell>!!Set 2::Enc 2!!</cell></row>
-  <row version="1.0"><cell>!!Set 1::Enc 3!!</cell><cell /></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="ninja" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 2" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 2" module="forms" name="Enc 2" version="1.0">
-  <text multiline="1" send_button="1">Hoot Hoot. It's an owl.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 2" module="forms" name="Enc 1" version="1.0">
-  <text multiline="1" send_button="1">Set 2 Random Encounter.</text>
-</nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 1" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 2" version="1.0">
-  <text multiline="1" send_button="1">Dark Elves.  Watch out!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 3" version="1.0">
-  <text multiline="1" send_button="1">Kobolds a plenty.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 1" version="1.0">
-  <text multiline="1" send_button="1">A Wandering Minotaur</text>
-</nodehandler></nodehandler></nodehandler></nodehandler><nodehandler class="file_loader" icon="help" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
-    <file name="die_roller_notes.xml" />
-  </nodehandler>
-  <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
-    <nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Templates" module="containers" name="PC Sheets" version="1.0">
-  <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create 4e PC Sheet" version="1.0">
-        <file name="4e_char_sheet.xml" />
-      </nodehandler><nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3.5 Tool" version="1.0">
-        <file name="dnd3.5.xml" />
+          </nodehandler>
+        </nodehandler>
+        </nodehandler>
+      <nodehandler class="form_handler" frame="409,414,422,76" height="600" icon="wizard1" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Deck" version="1.0" width="400">
+        <nodehandler class="rpg_grid_handler" frame="400,400,425,69" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Deck" module="rpg_grid" name="52 Card Deck" version="1.0">
+          <grid autosize="1" border="1">
+            <row version="1.0">
+              <cell>AS</cell>
+              <cell>AD</cell>
+              <cell>AC</cell>
+              <cell>AH</cell>
+            </row>
+            <row version="1.0">
+              <cell>KS</cell>
+              <cell>KD</cell>
+              <cell>KC</cell>
+              <cell>KH</cell>
+            </row>
+            <row version="1.0">
+              <cell>QS</cell>
+              <cell>QD</cell>
+              <cell>QC</cell>
+              <cell>QH</cell>
+            </row>
+            <row version="1.0">
+              <cell>JS</cell>
+              <cell>JD</cell>
+              <cell>JC</cell>
+              <cell>JH</cell>
+            </row>
+            <row version="1.0">
+              <cell>10S</cell>
+              <cell>10D</cell>
+              <cell>10C</cell>
+              <cell>10H</cell>
+            </row>
+            <row version="1.0">
+              <cell>9S</cell>
+              <cell>9D</cell>
+              <cell>9C</cell>
+              <cell>9H</cell>
+            </row>
+            <row version="1.0">
+              <cell>8S</cell>
+              <cell>8D</cell>
+              <cell>8C</cell>
+              <cell>8H</cell>
+            </row>
+            <row version="1.0">
+              <cell>7S</cell>
+              <cell>7D</cell>
+              <cell>7C</cell>
+              <cell>7H</cell>
+            </row>
+            <row version="1.0">
+              <cell>6S</cell>
+              <cell>6D</cell>
+              <cell>6C</cell>
+              <cell>6H</cell>
+            </row>
+            <row version="1.0">
+              <cell>5S</cell>
+              <cell>5D</cell>
+              <cell>5C</cell>
+              <cell>5H</cell>
+            </row>
+            <row version="1.0">
+              <cell>4S</cell>
+              <cell>4D</cell>
+              <cell>4C</cell>
+              <cell>4H</cell>
+            </row>
+            <row version="1.0">
+              <cell>3S</cell>
+              <cell>3D</cell>
+              <cell>3C</cell>
+              <cell>3H</cell>
+            </row>
+            <row version="1.0">
+              <cell>2S</cell>
+              <cell>2D</cell>
+              <cell>2C</cell>
+              <cell>2H</cell>
+            </row>
+          </grid>
+          <macros>
+            <macro name="" />
+          </macros>
+        </nodehandler>
+        <nodehandler class="textctrl_handler" frame="400,90,320,145" icon="note" map="Traipse OpenRPG::Bonus Nodes::Deck" module="forms" name="Draw" version="1.0">
+          <text hide_title="0" multiline="0" raw_mode="1" send_button="1">!=52 Card Deck::([#1d13], [#1d4])=!</text>
+        </nodehandler>
+        </nodehandler>
+      <nodehandler class="form_handler" frame="400,400,501,72" height="600" icon="orc" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Encounters" version="1.0" width="400">
+        <nodehandler class="listbox_handler" frame="400,153,348,150" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="forms" name="Roll" version="1.0">
+          <list hide_title="0" raw_mode="1" send_button="1" type="1">
+            <option caption="" selected="0" value="">!=Chart::([#1d3],1)=!</option>
+            <option caption="" selected="1" value="">!=Chart::([#1d2],2)=!</option>
+          </list>
+        </nodehandler>
+        <nodehandler class="rpg_grid_handler" frame="400,400,0,48" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="rpg_grid" name="Chart" version="1.0">
+          <grid autosize="0" border="1">
+            <row version="1.0">
+              <cell size="119">!=Set 1::Enc 1=!</cell>
+              <cell size="115">!=Set 2::Enc 1=!</cell>
+            </row>
+            <row version="1.0">
+              <cell>!=Set 1::Enc 2=!</cell>
+              <cell>!=Set 2::Enc 2=!</cell>
+            </row>
+            <row version="1.0">
+              <cell>!=Set 1::Enc 3=!</cell>
+              <cell />
+            </row>
+          </grid>
+          <macros>
+            <macro name="" />
+          </macros>
+        </nodehandler>
+        <nodehandler border="1" class="group_handler" cols="1" icon="ninja" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 2" version="1.0">
+          <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 2" module="forms" name="Enc 2" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">Hoot Hoot. It's an owl.</text>
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 2" module="forms" name="Enc 1" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">Set 2 Random Encounter.</text>
+          </nodehandler>
+          </nodehandler>
+        <nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 1" version="1.0">
+          <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 2" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">Dark Elves.  Watch out!</text>
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 3" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">Kobolds a plenty.</text>
+          </nodehandler>
+          <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 1" version="1.0">
+            <text hide_title="0" multiline="1" raw_mode="0" send_button="1">A Wandering Minotaur</text>
+          </nodehandler>
+          </nodehandler>
+        </nodehandler>
+      <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Bonus Nodes" module="containers" name="Devin Knight Miniatures" version="1.0">
+  <nodehandler class="minilib_handler" frame="400,495,0,47" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Devin Knight Miniatures" module="minilib" name="Kobolds" version="1.0"><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Dead 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-VWFxAXmoTpYse2buZiS4SZpzatg/pv_deadKobold1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Dead 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-KTugmfksrE56cHwgcV3PbC6Cg1o/pv_deadkobold2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Archer 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-Ti3EZB9ADZfoRXw2uLMiVViQGj8/pv_koboldarcher1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Archer 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-P-lXPtzQPE9guLwJk6D5zwusTn0/pv_koboldarcher2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Archer 3" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-qnxWFx32WXZBCPi6zvxYt_MdBpw/pv_koboldarcher3.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Chief 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-n2QA3bBoWlJaMLV_uBFAbjrZEE8/pv_koboldchief1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Chief 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-O8solKliwBfGxEqV2xAxb4ZGZo0/pv_koboldchief2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-JlgEsTT3lksr0W26RfE7NduLMt8/pv_koboldfighter1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-sjN5rqyKKJ7rQyzrpo8ciKOsSZY/pv_koboldfighter2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 3" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-yYytJ5NBMbnupiR8-7-P15ML2PE/pv_koboldfighter3.png" width="0" /></nodehandler><nodehandler class="minilib_handler" frame="400,495,0,47" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Devin Knight Miniatures" module="minilib" name="Goblins" version="1.0"><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Dead 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-EbZhcvjWbMlu4OdaFoPxb0Vvzsg/pv_deadgoblin1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Dead 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-wQYxU0aEuH9z6vP7c5ocH5NDL3g/pv_deadgoblin2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Cross Bow" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-pvrbiVb90pFepUrRGKFqOaGY01U/pv_goblinxbow1.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Archer 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-XxS8bDq5aquNE21bsjA6YI4m9j0/pv_goboarcher.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Archer 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-DY0Ihjm1A3EnVee2QEN0w2KbJsc/pv_goboarcher2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-1b5FhrUFEwQKQFW6syNIIXjlJqI/pv_gobofighter.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-Vrcik3LLM_tTVV0zot9bTFt8E00/pv_gobofighter2.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 3" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-6AElcQwzQQWFnWyrFgHdArcfboY/pv_gobofighter3.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 4" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-HvfD9Bi385v2reNtM5tBhbrkLSM/pv_gobofighter4.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Fighter 5" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-qDZgsrZCEJ7jOPnVEOEpVqetR8w/pv_gobofighter5.png" width="0" /></nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Bonus Nodes::Devin Knight Miniatures" module="containers" name="Aliens" version="1.0">
+  <nodehandler class="minilib_handler" frame="400,495,170,126" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Devin Knight Miniatures::Aliens" module="minilib" name="Green Aliens" version="1.0"><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV--RYuH3OGewjkqfxlypn0SkcweoI/pv_aliensGreenlo_33.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-gtgpviTFGC2nmyKrTNuXFGnPww4/pv_aliensGreenlo_34.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 3" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-4pQot88_GagRH_Pi5NhwHRWkDm0/pv_aliensGreenlo_35.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 4" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-u3ld_4ogWeJFqJvVme4VwUiJs6Y/pv_aliensGreenlo_36.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green Archer 1" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-gFpKPLnuvVRuubqu4naLxog3Miw/pv_aliensGreenlo_37.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green Archer 2" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-Zbnh_UgCs8y45e_Ued9LhNrSiqY/pv_aliensGreenlo_38.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green Magic User" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-GIWg-79YYQ0UtaHFBGRJPnfHYCI/pv_aliensGreenlo_39.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 5" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-WputA55KIvBPm_ePwOh4GWdvRF8/pv_aliensGreenlo_40.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 6" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-JEzg3yqjroxkFP-yDYf-m7q2_Ts/pv_aliensGreenlo_41.png" width="0" /><miniature align="0" face="0" heading="0" height="0" hide="0" locked="0" name="Green 7" posx="0" posy="0" unique="0" url="http://my.pogoplug.com/feeds/ewHgA4kMz3sZUz91kIGvFQ/XCEPV-dKZ_WoKKSt2_0Z849xT_kqhZ2WQ/pv_aliensGreenlo_42.png" width="0" /></nodehandler></nodehandler></nodehandler></nodehandler>
+    <nodehandler class="file_loader" icon="book" map="Traipse OpenRPG" module="core" name="Load User Manual" version="1.0">
+      <file name="Traipse_User_Guide.xml" />
+    </nodehandler>
+    <nodehandler class="file_loader" icon="d10" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
+      <file name="die_roller_notes.xml" />
+    </nodehandler>
+    <nodehandler border="1" class="group_handler" cols="1" icon="grid" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
+      <nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Templates" module="containers" name="PC Sheets" version="1.0">
+        <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3.5 Tool" version="1.0">
+          <file name="dnd3.5.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create WH PC Sheet" version="1.0">
+  <file name="Warhammerv2CS2-Traipse.xml" />
+</nodehandler><nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create 4e PC Sheet" version="1.0">
+          <file name="4e_char_sheet.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3rd Edition Character Tool" version="1.0">
+          <file name="dnd3e.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New St*r W*rs Character Tool" version="1.0">
+          <file name="StarWars_d20character.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New d20 Character Tool" version="1.0">
+          <file name="d20character.xml" />
+        </nodehandler>
+        </nodehandler>
+      <nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
+        <nodehandler class="file_loader" icon="note" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Text Box" version="1.0">
+          <file name="textctrl.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New List Box" version="1.0">
+          <file name="listbox.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="grid" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Grid" version="1.0">
+          <file name="grid.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="html" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Web Link" version="1.0">
+          <file name="link.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="image" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Web Image" version="1.0">
+          <file name="image.xml" />
+        </nodehandler>
+        </nodehandler>
+      <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Templates" module="containers" name="Containers" status="useful" version="1.0">
+        <nodehandler class="file_loader" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Folder" version="1.0">
+          <file name="group.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="tabber" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Tabber" version="1.0">
+          <file name="tabber.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="divider" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Splitter" version="1.0">
+          <file name="split.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="form" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Form" version="1.0">
+          <file name="form.xml" />
+        </nodehandler>
+        </nodehandler>
+      <nodehandler border="1" class="group_handler" cols="1" icon="grenade" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
+        <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create File Loader" version="1.0">
+          <file name="file_loader.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
+          <file name="macro.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Miniature Library Tool" version="1.0">
+          <file name="minlib.xml" />
+        </nodehandler>
+        <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create Remote Node Loader" version="1.0">
+          <file name="urloader.xml" />
+        </nodehandler>
+        </nodehandler>
       </nodehandler>
-    <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="3rd Edition Character Tool" version="1.0">
-        <file name="dnd3e.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New St*r W*rs Character Tool" version="1.0">
-        <file name="StarWars_d20character.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New d20 Character Tool" version="1.0">
-        <file name="d20character.xml" />
+    <nodehandler border="1" class="group_handler" cols="1" icon="browser" map="Traipse OpenRPG" module="containers" name="OpenRPG+ Resources" version="1.0">
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG+ Home Page" version="1.0">
+        <link href="http://www.openrpg.com" />
       </nodehandler>
-      </nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
-      <nodehandler class="file_loader" icon="note" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Text Box" version="1.0">
-        <file name="textctrl.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New List Box" version="1.0">
-        <file name="listbox.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="grid" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Grid" version="1.0">
-        <file name="grid.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="html" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Web Link" version="1.0">
-        <file name="link.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="image" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Web Image" version="1.0">
-        <file name="image.xml" />
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Forums" version="1.0">
+        <link href="http://forums.rpghost.com/forumdisplay.php?s=&amp;forumid=118" />
       </nodehandler>
-    </nodehandler>
-    <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Templates" module="containers" name="Containers" status="useful" version="1.0">
-      <nodehandler class="file_loader" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Folder" version="1.0">
-        <file name="group.xml" />
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Plugin HQ" version="1.0">
+        <link href="http://openrpg.mduo13.com/plugins.php" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="tabber" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Tabber" version="1.0">
-        <file name="tabber.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="divider" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Splitter" version="1.0">
-        <file name="split.xml" />
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Web Ring" version="1.0">
+        <link href="http://www.ringsurf.com/netring?ring=OpenRPG;action=home" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="form" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Form" version="1.0">
-        <file name="form.xml" />
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="AutoRealm" version="1.0">
+        <link href="http://autorealm.sourceforge.net/" />
       </nodehandler>
-    </nodehandler>
-    <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Die Macro" version="1.0">
-        <file name="die_macro.xml" />
-      </nodehandler><nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
-        <file name="macro.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Miniature Library Tool" version="1.0">
-        <file name="minlib.xml" />
-      </nodehandler>
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create remote node loader" version="1.0">
-        <file name="urloader.xml" />
+      <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="PCGen" version="1.0">
+        <link href="http://pcgen.sourceforge.net/01_overview.php" />
       </nodehandler>
       </nodehandler>
-  </nodehandler>
-  <nodehandler border="1" class="group_handler" cols="1" icon="browser" map="Traipse OpenRPG" module="containers" name="OpenRPG+ Resources" version="1.0">
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG+ Home Page" version="1.0">
-      <link href="http://www.openrpg.com" />
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Forums" version="1.0">
-      <link href="http://forums.rpghost.com/forumdisplay.php?s=&amp;forumid=118" />
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Plugin HQ" version="1.0">
-      <link href="http://openrpg.mduo13.com/plugins.php" />
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG Web Ring" version="1.0">
-      <link href="http://www.ringsurf.com/netring?ring=OpenRPG;action=home" />
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="AutoRealm" version="1.0">
-      <link href="http://www.gryc.ws/autorealm.htm" />
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="PCGen" version="1.0">
-      <link href="http://pcgen.sourceforge.net/01_overview.php" />
-    </nodehandler>
-  </nodehandler>
-  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG" module="containers" name="Examples (Adventures)" version="1.0">
-    <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Examples (Adventures)" module="core" name="Bastion Press d20 Adventure" version="1.0">
-      <file name="Bastion_adventure.xml" />
-    </nodehandler>
-    <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Examples (Adventures)" module="core" name="Darwin&apos;s World d20 Adventure" version="1.0">
-      <file name="Darwin_adventure.xml" />
-    </nodehandler>
-  </nodehandler>
-</nodehandler>
\ No newline at end of file
+    <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG" module="containers" name="Examples (Adventures)" version="1.0">
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Examples (Adventures)" module="core" name="Bastion Press d20 Adventure" version="1.0">
+        <file name="Bastion_adventure.xml" />
+      </nodehandler>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Examples (Adventures)" module="core" name="Darwin&apos;s World d20 Adventure" version="1.0">
+        <file name="Darwin_adventure.xml" />
+      </nodehandler>
+      </nodehandler>
+  </nodehandler>
\ No newline at end of file
--- a/orpg/templates/nodes/4e_char_sheet.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/4e_char_sheet.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -1,4 +1,4 @@
-<nodehandler class="tabber_handler" frame="808,494,162,44" icon="tabber" map="" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="tabber_handler" frame="400,400,399,89" icon="tabber" map="4e PC Sheet" module="containers" name="Using the 4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This node is designed to be as generic as possible. It should contain the core basics for users to fill out with game information that is specific to their character.
+<nodehandler class="tabber_handler" frame="808,494,166,146" icon="tabber" map="" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="tabber_handler" frame="400,400,399,89" icon="tabber" map="4e PC Sheet" module="containers" name="Using the 4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This node is designed to be as generic as possible. It should contain the core basics for users to fill out with game information that is specific to their character.
 
 The node is also designed to be organized with speed of use in mind. Since the majority of nodes are inside Tabbers you can easily use the top node and find all of your data inside. In fact, that is how I am writing this.
 
@@ -30,29 +30,29 @@
 ** I went with this format so users could create their Utility nodes and share with others. The nodes can contain Role Play information as well as attack and damage rolls. Also, the nodes can be completely genric, referencing the Name Text node and still look specific **</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Inventory" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">It's just a node to hold your Inventory
 
 This bears repeating:
-It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="437,400,373,67" icon="tabber" map="4e PC Sheet" module="containers" name="Rollers" version="1.0"><nodehandler class="listbox_handler" frame="400,400,430,57" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Skills" version="1.0">
-        <list raw_mode="1" send_button="1" type="1">
-          <option caption="" selected="1" value="0">Climb [1d20+5+!#Abilities::(1,3)#!+(!#General::Level#!/2)</option>
-          <option caption="" selected="0" value="0">Hide [1d20+5+!#Abilities::(2,3)#!+(!#General::Level#!/2)]</option>
-          <option caption="" selected="0" value="0">Spot [1d20+5+!#Abilities::(4,3)#!+(!#General::Level#!/2)]</option>
+It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="568,400,446,121" icon="tabber" map="4e PC Sheet" module="containers" name="Rollers" version="1.0"><nodehandler class="listbox_handler" frame="400,400,541,107" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Skills" version="1.0">
+        <list raw_mode="1" send_button="1" type="2">
+          <option caption="Climb" selected="0" value="0">&lt;b&gt;Climb:&lt;/b&gt; [1d20+5+!=Abilities::(1,3)=!+(!=General::Level=!/2)]</option>
+          <option caption="Hide" selected="1" value="0">&lt;b&gt;Hide:&lt;/b&gt; [1d20+5+!=Abilities::(2,3)=!+(!=General::Level=!/2)]</option>
+          <option caption="Spot" selected="0" value="0">&lt;b&gt;Spot:&lt;/b&gt; [1d20+5+!=Abilities::(4,3)=!+(!=General::Level=!/2)]</option>
         </list>
       </nodehandler>
-      <nodehandler class="listbox_handler" frame="400,400,477,43" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Attacks" version="1.0">
+      <nodehandler class="listbox_handler" frame="400,400,450,100" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Attacks" version="1.0">
   <list raw_mode="1" send_button="1" type="1">
-    <option caption="Sword Attack" selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(2,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(2,2)#!]</option>
-    <option caption="Mace Attack" selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(3,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(3,2)#!]</option>
+    <option caption="Sword Attack" selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !=Combat::Weapons::2,1=! [1d20+!=Combat::To Hit::2,2=!] &lt;b&gt;Damage:&lt;/b&gt; [1!=Combat::Weapons::2,2=!+!=Abilities::1,3=!]</option>
+    <option caption="Mace Attack" selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !=Combat::Weapons::3,1=! [1d20+!=Combat::To Hit::2,2=!] &lt;b&gt;Damage:&lt;/b&gt; [1!=Combat::Weapons::3,2=!+!=Abilities::1,3=!]</option>
     <option caption="Uncreated" selected="0" value="">Option Text III</option>
   </list>
 </nodehandler><nodehandler class="splitter_handler" frame="764,400,9,91" horizontal="0" icon="divider" map="4e PC Sheet::Rollers" module="containers" name="Powers" version="1.0">
     <nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="At Wills" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option caption="At Will Power" selected="1" value="0">!#Utilities::At Will::0::At Will#!</option></list>
+  <list raw_mode="1" send_button="1" type="3">
+    <option caption="At Will Power" selected="1" value="0">!=Utilities::At Wills::At Will=!</option></list>
 </nodehandler><nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Encounters" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option caption="Encounter" selected="1" value="0">!#Utilities::Encounter::0::Encounter#!</option></list>
+  <list raw_mode="1" send_button="1" type="3">
+    <option caption="Encounter" selected="1" value="0">!=Utilities::Encounters::Encounter=!</option></list>
 </nodehandler><nodehandler class="listbox_handler" frame="400,400,470,62" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Dailys" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option caption="Daily" selected="1" value="0">!#Utilities::Daily::0::Daily#!</option></list>
+  <list raw_mode="1" send_button="1" type="3">
+    <option caption="Daily" selected="1" value="0">!=Utilities::Dailys::Daily=!</option></list>
 </nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet" module="forms" name="General" version="1.0" width="400">
   <nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Name" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">text</text>
@@ -66,51 +66,7 @@
   <text multiline="0" raw_mode="1" send_button="0">1</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Tier" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">1</text>
-</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet" module="rpg_grid" name="Abilities" version="1.0">
-        <grid autosize="1" border="1">
-          <row version="1.0">
-            <cell>Str</cell>
-            <cell>8</cell>
-          <cell size="197">(!!Abilities::(1,2)!!-10)/2</cell></row>
-          <row version="1.0">
-            <cell>Dex</cell>
-            <cell>8</cell>
-          <cell>(!!Abilities::(2,2)!!-10)/2</cell></row>
-          <row version="1.0">
-            <cell>Con</cell>
-            <cell>8</cell>
-          <cell>(!!Abilities::(3,2)!!-10)/2</cell></row>
-          <row version="1.0">
-            <cell>Int</cell>
-            <cell>8</cell>
-          <cell>(!!Abilities::(4,2)!!-10)/2</cell></row>
-          <row version="1.0">
-            <cell>Wis</cell>
-            <cell>8</cell>
-          <cell>(!!Abilities::(5,2)!!-10)/2</cell></row>
-          <row version="1.0">
-            <cell>Cha</cell>
-            <cell>8</cell>
-          <cell>(!!Abilities::(6,2)!!-10)/2</cell></row>
-        </grid>
-        <macros>
-          <macro name="" />
-        </macros>
-      </nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="To Hit" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Armor</cell>
-      <cell>Bonus</cell>
-    </row>
-    <row version="1.0">
-      <cell>Total</cell>
-      <cell>!!To Hit::(2,3)!! + !!To Hit::(2,4)!!</cell>
-    </row>
-  <row version="1.0"><cell>BAB</cell><cell>0</cell></row><row version="1.0"><cell>Str Mod</cell><cell>!#Abilities::(1,3)#!</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,269,110" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="400,400,269,110" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell>Weapon</cell>
@@ -120,7 +76,21 @@
       <cell>Sword</cell>
       <cell>d6</cell>
     </row>
-  <row version="1.0"><cell>Mace</cell><cell>d8</cell></row></grid>
+  <row version="1.0"><cell>Mace</cell><cell>d8</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="To Hit" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell size="360">Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!=To Hit::(3,2)=! + !=To Hit::(4,2)=!</cell>
+    </row>
+  <row version="1.0"><cell>BAB</cell><cell>15</cell></row><row version="1.0"><cell>Str Mod</cell><cell>!=Abilities::(1,3)=!</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
   <macros>
     <macro name="" />
   </macros>
@@ -128,13 +98,13 @@
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell>Armor</cell>
-      <cell>Bonus</cell>
+      <cell size="225">Bonus</cell>
     </row>
     <row version="1.0">
       <cell>Total</cell>
-      <cell>!!AC Bonus::(2,3)!!</cell>
+      <cell>!=AC Bonus::(3,2)=!+!=AC Bonus::(4,2)=!</cell>
     </row>
-  <row version="1.0"><cell>Misc</cell><cell>0</cell></row></grid>
+  <row version="1.0"><cell>Armor</cell><cell>!!Armor::(2,2)!!</cell></row><row version="1.0"><cell>Misc</cell><cell>0</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
   <macros>
     <macro name="" />
   </macros>
@@ -142,13 +112,13 @@
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell>Armor</cell>
-      <cell>Bonus</cell>
+      <cell size="183">Bonus</cell>
     </row>
     <row version="1.0">
       <cell>Total</cell>
-      <cell>!!Armor::(2,3)!!</cell>
+      <cell>!=Armor::(3,2)=!</cell>
     </row>
-  <row version="1.0"><cell>Base</cell><cell>10</cell></row></grid>
+  <row version="1.0"><cell>Base</cell><cell>10</cell></row><row version="1.0"><cell>Armor</cell><cell /></row><row version="1.0"><cell>Shield</cell><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
   <macros>
     <macro name="" />
   </macros>
@@ -156,28 +126,64 @@
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell>Armor</cell>
-      <cell>Bonus</cell>
+      <cell size="106">Bonus</cell>
     <cell>Descripton</cell></row>
     <row version="1.0">
       <cell>Total</cell>
-      <cell>!!Feats(2,3)!!</cell>
+      <cell>!=Feats::(3,2)=!</cell>
     <cell /></row>
-  <row version="1.0"><cell>Feat</cell><cell>0</cell><cell /></row></grid>
+  <row version="1.0"><cell>Feat</cell><cell>0</cell><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row></grid>
   <macros>
     <macro name="" />
   </macros>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,407,67" icon="tabber" map="4e PC Sheet" module="containers" name="Utilities" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="At Will" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::At Will::0" module="forms" name="At Will" version="1.0">
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet" module="rpg_grid" name="Abilities" version="1.0">
+        <grid autosize="1" border="1">
+          <row version="1.0">
+            <cell>Str</cell>
+            <cell>12</cell>
+          <cell size="197">(!=Abilities::(1,2)=!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Dex</cell>
+            <cell>8</cell>
+          <cell>(!=Abilities::(2,2)=!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Con</cell>
+            <cell>14</cell>
+          <cell>(!=Abilities::(3,2)=!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Int</cell>
+            <cell>18</cell>
+          <cell>(!=Abilities::(4,2)=!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Wis</cell>
+            <cell>8</cell>
+          <cell>(!=Abilities::(5,2)=!-10)/2</cell></row>
+          <row version="1.0">
+            <cell>Cha</cell>
+            <cell>8</cell>
+          <cell>(!=Abilities::(6,2)=!-10)/2</cell></row>
+        </grid>
+        <macros>
+          <macro name="" />
+        </macros>
+      </nodehandler><nodehandler class="tabber_handler" frame="400,400,407,67" icon="tabber" map="4e PC Sheet" module="containers" name="Utilities" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="At Wills" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Wills" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::At Wills::0" module="forms" name="At Will" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an At Will
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Encounter" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Encounter::0" module="forms" name="Encounter" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Wills" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Encounters" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounters" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Encounters::0" module="forms" name="Encounter" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an Encounter
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Daily" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Daily::0" module="forms" name="Daily" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounters" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Dailys" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Dailys" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Dailys::0" module="forms" name="Daily" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an Daily
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="1" version="1.0" /></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Inventory" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory" module="forms" name="Back Pack" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">Empty.</text>
-</nodehandler></nodehandler></nodehandler>
\ No newline at end of file
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Dailys" module="containers" name="1" version="1.0" /></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Inventory" version="1.0"><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Inventory" module="containers" name="Back pack" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory::Back pack" module="forms" name="Slot 1" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory::Back pack" module="forms" name="Slot 2" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Inventory" module="containers" name="Belt" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory::Belt" module="forms" name="Slot 1" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory::Belt" module="forms" name="Slot 2" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler></nodehandler></nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/templates/nodes/split.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/split.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -1,3 +1,2 @@
-  <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-    <splitter_atts horizontal="0"/>
-  </nodehandler>
\ No newline at end of file
+  <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0" horizontal="0">
+  </nodehandler>
--- a/orpg/templates/nodes/textctrl.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/textctrl.xml	Sat Jun 12 03:50:37 2010 -0500
@@ -1,4 +1,1 @@
-
-<nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-  <text multiline="0" send_button="0">text</text>
-</nodehandler>
+<nodehandler class="textctrl_handler" frame="334,115,288,148" icon="note" map="" module="forms" name="Text" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="1">Text</text></nodehandler>
\ No newline at end of file
--- a/orpg/tools/FlatNotebook.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/FlatNotebook.py	Sat Jun 12 03:50:37 2010 -0500
@@ -74,6 +74,7 @@
 # Beginning Of FLATNOTEBOOK wxPython Code
 #----------------------------------------------------------------------
 
+print 'Flatnotebook'
 import wx
 import random
 import math
--- a/orpg/tools/aliaslib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/aliaslib.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: aliaslib.py,v 1.20 2007/08/09 05:23:21 digitalxero Exp $
+#   $Id: aliaslib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for alias.
 #
 
-__version__ = "$Id: aliaslib.py,v 1.20 2007/08/09 05:23:21 digitalxero Exp $"
+__version__ = "$Id: aliaslib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import component
@@ -35,6 +35,7 @@
 from orpg.dirpath import dir_struct
 from orpg.tools.validate import validate
 from orpg.tools.orpg_settings import settings
+from xml.etree.ElementTree import tostring, parse
 import re
 
 class AliasLib(wx.Frame):
@@ -174,7 +175,6 @@
         f.close()
 
     def OnMB_FileExportToTree(self, event):
-        #tree = component.get("tree")
         xml = '<nodehandler class="voxchat_handler" '
         xml += 'icon="player" '
         xml += 'module="voxchat" '
@@ -459,36 +459,30 @@
         self.Fit()
 
     def loadFile(self):
-        f = open(dir_struct["user"] + self.filename, "r")
-        data = f.read()
-        f.close()
-        self.alias = -1
-        self.filter = -1
-        xml_dom = component.get('xml').parseXml(data)
-        del data
-        aliases = xml_dom.getElementsByTagName("alias")
+        data = parse(dir_struct["user"] + self.filename)
+        xml_dom = data.getroot()
+        aliases = xml_dom.findall("alias")
         alist = []
         for alias in aliases:
-            if alias.hasAttribute("color"): color = alias.getAttribute("color")
+            if alias.get("color"): color = alias.get("color")
             else: color = 'Default'
-            aname = self.MakeSafeHTML(alias.getAttribute("name"))
+            aname = self.MakeSafeHTML(alias.get("name"))
             alist.append([aname, color])
         alist.sort()
         self.aliasList = alist
-        filters = xml_dom.getElementsByTagName("filter")
+        filters = xml_dom.findall("filter")
         flist = []
         self.regExList = []
         for filter in filters:
-            flist.append(filter.getAttribute("name"))
-            rules = filter.getElementsByTagName("rule")
+            flist.append(filter.get("name"))
+            rules = filter.findall("rule")
             sub = []
-            for rule in rules: sub.append([self.MakeSafeHTML(rule.getAttribute("match")), 
-                                        self.MakeSafeHTML(rule.getAttribute("sub"))])
+            for rule in rules: sub.append([self.MakeSafeHTML(rule.get("match")), 
+                                        self.MakeSafeHTML(rule.get("sub"))])
             self.regExList.append(sub)
         self.filterList = flist
-        xml_dom.unlink()
-        self.alias = -1
-        self.filter = -1
+        self.alias = 0
+        self.filter = 0
 
     def MakeSafeHTML(self, str):
         return str.replace("&amp;", "&").replace("&lt;", "<").replace("&quot;", '"').replace("&gt;", ">").replace("&#39;", "'")
@@ -496,7 +490,7 @@
         return str.replace("&", "&amp;").replace("<", "&lt;").replace('"', "&quot;").replace(">", "&gt;").replace("'", "&#39;")
     def ImportFromTree(self, xml_dom):
         oldfilename = self.filename
-        if xml_dom.getAttribute('name') == 'Alias Library':
+        if xml_dom.get('name') == 'Alias Library':
             dlg = wx.TextEntryDialog(self, "Please Name This Alias Lib", "New Alias Lib")
             if dlg.ShowModal() == wx.ID_OK:
                 self.filename = dlg.GetValue() + '.alias'
@@ -504,11 +498,11 @@
             else:
                 dlg.Destroy()
                 return
-        else: self.filename = xml_dom.getAttribute('name') + '.alias'
+        else: self.filename = xml_dom.get('name') + '.alias'
         settings.set_setting('aliasfile', self.filename[:-6])
         if oldfilename != self.filename: self.OnMB_FileSave(None, oldfilename)
         f = open(dir_struct["user"] + self.filename, "w")
-        f.write(xml_dom.toxml().replace('nodehandler', 'aliaslib').replace('voxchat.', ''))
+        f.write(tostring(xml_dom).replace('nodehandler', 'aliaslib').replace('voxchat.', ''))
         f.close()
         wx.CallAfter(self.loadFile)
 
@@ -689,8 +683,6 @@
         self.regExList[self.filterIdx] = list
 
     def FormatText(self, event):
-        #self.textColorBtn = wx.Button(self, wx.ID_ANY, "Color")
-        #self.textColorBtn.SetForegroundColour(wx.BLACK)
         id = event.GetId()
         txt = self.textWnd.GetValue()
         (beg, end) = self.textWnd.GetSelection()
--- a/orpg/tools/inputValidator.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/inputValidator.py	Sat Jun 12 03:50:37 2010 -0500
@@ -25,7 +25,7 @@
 # user input generated text.
 #
 
-__version__ = "$Id: inputValidator.py,v 1.11 2006/11/04 21:24:22 digitalxero Exp $"
+__version__ = "$Id: inputValidator.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
--- a/orpg/tools/orpg_log.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/orpg_log.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: orpg_log.py,v 1.9 2007/05/06 16:43:02 digitalxero Exp $
+#   $Id: orpg_log.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: classes for orpg log messages
 #
@@ -62,7 +62,7 @@
     def write(self, text):
         logger.stdout(text)
         wx.Yield()
-        #sys.__stdout__.write(text)
+        sys.__stdout__.write(text)
 
 class TrueDebug(object):
     """A simple debugger. Add debug() to a function and it prints the function name and any objects included. Add an object or a group of objects in ()'s.
@@ -102,13 +102,15 @@
         self.report = wx.Button(self, wx.ID_ANY, 'Bug Report')
         sizer = wx.GridBagSizer(hgap=1, vgap=1)
         sizer.Add(self.console, (0,0), span=(1,2), flag=wx.EXPAND)
-        sizer.Add(self.bt_clear, (1,0), flag=wx.ALIGN_LEFT)
-        sizer.Add(self.report, (1,1), flag=wx.ALIGN_LEFT)
+        sizer.Add(self.bt_clear, (1,0), span=(1,1), flag=wx.ALIGN_LEFT)
+        sizer.Add(self.report, (1,1), span=(1,1), flag=wx.ALIGN_RIGHT|wx.EXPAND)
         sizer.AddGrowableCol(0)
         sizer.AddGrowableRow(0)
         self.SetSizer(sizer)
+        #self.Layout()
         self.SetAutoLayout(True)
-        self.SetSize((450, 175))
+        self.SetSize((450, 275))
+        self.SetMinSize((450, 275))
         self.Bind(wx.EVT_CLOSE, self.Min) 
         self.Bind(wx.EVT_BUTTON, self.clear, self.bt_clear)
         self.Bind(wx.EVT_BUTTON, self.bug_report, self.report)
--- a/orpg/tools/orpg_settings.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/orpg_settings.py	Sat Jun 12 03:50:37 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
@@ -183,14 +183,17 @@
 
     def dieroller_ok(self, changes):
         rm = component.get('DiceManager')
+        cur_die = rm.getRoller()
         try:
             rm.setRoller(changes)
             self.chat.SystemPost('You have changed your die roller to the <b>"' + rm.getRoller() + '"</b> roller.')
         except Exception, e:
-            print e
             rm.setRoller('std')
-            self.settings.change('dieroller', 'std')
-            self.chat.SystemPost('<b>"' + changes + '"</b> is an invalid roller. Setting roller to <b>"std"</b>')
+            rm.setRoller(cur_die)
+            self.settings.change('dieroller', cur_die)
+            self.chat.SystemPost('<b>"' + changes + '"</b> is an invalid roller.')
+            self.chat.InfoPost('Available die rollers: ' +str(rm.listRollers()) )
+            self.chat.InfoPost('You are using the <b>"' +cur_die+ '"</b> die roller.')
 
     def colortree_ok(self, changes):
         top_frame = component.get('frame')
@@ -306,4 +309,3 @@
         for i in range(0,cols): self.SetColSize(i,col_w)
         self.Refresh()
 
-#settings = orpg.tools.settings.Settings()
--- a/orpg/tools/passtool.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/passtool.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Todd "Snowdog" Faris
 # Maintainer:
 # Version:
-#   $Id: passtool.py,v 1.9 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: passtool.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: password helper. remembers passwords so user
 #              doesn't have to type passwords over and over
--- a/orpg/tools/predTextCtrl.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/predTextCtrl.py	Sat Jun 12 03:50:37 2010 -0500
@@ -60,48 +60,17 @@
         return self.asciiChar
 
 
-# This class implements the tree structure to hold the words
-#
-# Defines:
-#    __init__(self,filename)
-#    updateMostCommon(self,target)
-#    setWord(self,wordText,priority,sumFlag)
-#    addWord(self,wordText)
-#    setWord(self,wordText)
-#    setWordPriority(self,wordText,priority)
-#    findWordNode(self,wordText) returns class Letter
-#    findWordPriority(self,wordText) returns int
-#    getPredition(self,k,cur) returns string
 class LetterTreeClass(object):
 
-    # Initialization subroutine.
-    #
-    # self : instance of self
-    # filename : name of word file to use
-    #
-    # returns None
-    #
-    # Purpose:  Constructor for LetterTree.  Basically, it initializes itself with a word file, if present.
     def __init__(self, singletonKey):
         if not isinstance(singletonKey, _SingletonKey):
             raise invalid_argument(_("Use LetterTree() to get access to singleton"))
 
-        self.rootNode = Letter("",None)                # rootNode is a class Letter
-        self.rootNode.children = {}                    # initialize the children list
-
+        self.rootNode = Letter("",None)                
+        self.rootNode.children = {} 
 
-    # updateMostCommon subroutine.
-    #
-    # self : instance of self
-    # target : class Letter that was updated
-    #
-    # Returns None
-    #
-    # Purpose:  Updates all of the parent nodes of the target, such that their mostCommon member
-    #           points to the proper class Letter, based on the newly updated priorities.
     def updateMostCommon(self, target):
-                                                # cur is a class Letter
-        prev = target.parentNode                # prev is a class Letter
+        prev = target.parentNode
         while prev:
             if prev.mostCommon is None:
                 prev.mostCommon = target
@@ -110,106 +79,44 @@
                     prev.mostCommon = target
             prev = prev.parentNode
 
-
+    def setWord(self,wordText,priority = 1,sumFlag = 0):
+        cur = self.rootNode                     
+        for ch in wordText:  
+            if cur.children.has_key(ch):
+                cur = cur.children[ch] 
+            else:  
+                newLetter = Letter(ch,cur)
+                if cur is self.rootNode:
+                    newLetter.parentNode = None
+                cur.children[ch] = newLetter
+                cur = newLetter  
+        if sumFlag: cur.priority += priority
+        else: cur.priority = priority 
+        self.updateMostCommon(cur) 
 
-    # setWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    # priority : integer priority to set the word
-    # sumFlag : if True, add the priority to the existing, else assign the priority
-    #
-    # Returns:  None
-    #
-    # Purpose:  Sets or increments the priority of a word, adding the word if necessary
-    def setWord(self,wordText,priority = 1,sumFlag = 0):
-        cur = self.rootNode                     # start from the root
-        for ch in wordText:                     # for each character in the word
-            if cur.children.has_key(ch):        # check to see if we've found a new word
-                cur = cur.children[ch]            # if we haven't found a new word, move to the next letter and try again
-            else:                               # in this clause, we're creating a new branch, as the word is new
-                newLetter = Letter(ch,cur)        # create a new class Letter using this ascii code and the current letter as a parent
-                if cur is self.rootNode:          # special case:  Others expect the top level letters to point to None, not self.rootNode
-                    newLetter.parentNode = None
-                cur.children[ch] = newLetter      #  add the new letter to the list of children of the current letter
-                cur = newLetter                   #  make the new letter the current one for the next time through
-
-        #  at this point, cur is pointing to the last letter of either a new or existing word.
-        if sumFlag: cur.priority += priority    #  if the caller wants to add to the existing (0 if new)
-        else: cur.priority = priority           #  else, the set the priority directly
-        self.updateMostCommon(cur)              # this will run back through the tree to fix up the mostCommon members
-
-    # addWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Used to add words known not to exist.
     def addWord(self,wordText):
         self.setWord(wordText,priority = 1)
 
-    # incWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Used to increment the priority of existing words and add new words.
-    # Note:     Generally, this method can be used instead of addWord.
-
     def incWord(self,wordText):
         self.setWord(wordText,priority = 1, sumFlag = 1)
 
-    # setWordPriority subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    # priority:  int that is the new priority
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Sets existing words to priority or adds new words with priority = priority
-
     def setWordPriority(self,wordText,priority):
         self.setWord(wordText,priority = priority)
 
 
-    # findWordNode subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  class Letter or None if word isn't found.
-    #
-    # Purpose:  Given a word, it returns the class Letter node that corresponds to the word.  Used mostly in prep for a call to
-    #           getPrediction()
-
-    def findWordNode(self,wordText):         #returns class Letter that represents the last letter in the word
-        cur = self.rootNode                  # start at the root
-        for ch in wordText:                  # move through each letter in the word
-            if cur.children.has_key(ch):     # if the next letter exists, make cur equal that letter and loop
+    def findWordNode(self,wordText):  
+        cur = self.rootNode 
+        for ch in wordText: 
+            if cur.children.has_key(ch):
                 cur = cur.children[ch]
-            else: return None                # return None if letter not found
-        return cur                           # return cur, as this points to the last letter if we got this far
-
-
-    # findWordPriority subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  Int representing the word's priority or 0 if not found.
-    #
-    # Purpose:  Returns the priority of the given word
+            else: return None  
+        return cur  
 
     def findWordPriority(self,wordText):
 
-        cur = self.findWordNode(wordText)    #  find the class Letter node that corresponds to this word
-        if cur: return cur.priority          #  if it was found, return it's priority
-        else: return 0                       #  else, return 0, meaning word not found
+        cur = self.findWordNode(wordText) 
+        if cur: return cur.priority
+        else: return 0 
 
     def printTree(self, current=None):
         letters = []
@@ -222,50 +129,18 @@
                 letters.append(m)
         return letters
 
-    # getPrediction subroutine.
-    #
-    # self : instance of self
-    # k : ASCII char that was typed
-    # cur : class Letter that points to the current node in LetterTree
-    #
-    # Returns:  The predicted text or "" if none found
-    #
-    # Purpose:  This is the meat and potatoes of data structure.  It takes the "current" Letter node and the next key typed
-    #           and returns it's guess of the rest of the word, based on the highest priority letter in the rest of the branch.
     def getPrediction(self,k,cur):
 
-        if cur.children.has_key(k) :                            #  check to see if the key typed is a sub branch
-                                                                #  If so, make a prediction.  Otherwise, do the else at the bottom of
-                                                                #  the method (see below).
-
-            cur = cur.children[k]                               #  set the cur to the typed key's class Letter in the sub-branch
-
-            backtrace = cur.mostCommon                          # backtrace is a class Letter.  It's used as a placeholder to back trace
-                                                                # from the last letter of the mostCommon word in the
-                                                                # sub-tree up through the tree until we meet ourself at cur.  We'll
-                                                                # build the guess text this way
-
-            returnText = ""                                     # returnText is a string.  This will act as a buffer to hold the string
-                                                                # we build.
-
-            while cur is not backtrace:                         #  Here's the loop.  We loop until we've snaked our way back to cur
-
-                returnText = backtrace.asciiChar + returnText   #  Create a new string that is the character at backtrace + everything
-                                                                #  so far.  So, for "tion"  we'll build "n","on","ion","tion" as we ..
-
-                backtrace = backtrace.parentNode                #  ... climb back towards cur
-
-            return returnText                                   #  And, having reached here, we've met up with cur, and returnText holds
-                                                                #  the string we built.  Return it.
-
-        else:                                                   #  This is the else to the original if.
-                                                                #  If the letter typed isn't in a sub branch, then
-                                                                #  the letter being typed isn't in our tree, so
-            return ""                                           #  return the empty string
-
-
-#  End of class LetterTree!
-
+        if cur.children.has_key(k) : 
+            cur = cur.children[k] 
+            backtrace = cur.mostCommon
+            returnText = ''
+            while cur is not backtrace: 
+                returnText = backtrace.asciiChar + returnText
+                backtrace = backtrace.parentNode 
+            return returnText 
+        else: 
+            return "" 
 
 
 class _SingletonKey(object):
@@ -277,62 +152,24 @@
 __key = _SingletonKey()
 LetterTree = LetterTreeClass(__key)
 
-# This class extends wx.TextCtrl
-#
-# Extends:  wx.TextCtrl
-#
-# Overrides:
-#    wx.TextCtrl.__init__(self,parent,id,value,size,style,name)
-#    wx.TextCtrl.OnChar(self,Event)
-#
-# Defines:
-#    findWord(self,insert,st)
+
 class predTextCtrl(ExpandoTextCtrl):
 
-    # Initialization subroutine.
-    #
-    # self : instance of self
-    # parent:  reference to parent window (wxWindow, me-thinks)
-    # id:      new Window Id, default to -1 to create new (I think: see docs for wxPython)
-    # value:   String that is the initial value the control holds, defaulting to ""
-    # size:    defaults to wx.DefaultSize
-    # style:   defaults to 0
-    # name:    defaults to "text"
-    # keyHook: must be a function pointer that takes self and a GetKeyCode object
-    # validator: defaults to None
-    #
-    # Note:  These parameters are essentially just passed back to the native wx.TextCtrl.
-    #        I basically just included (stole) enough of them from chatutils.py to make
-    #        it work.  Known missing args are pos and validator, which aren't used by
-    #        chatutils.py.
-    #
-    # Returns:  None
-    #
-    # Purpose:  Constructor for predTextCtrl.  Calls wx.TextCtrl.__init__ to get default init
-    #           behavior and then inits a LetterTree and captures the parent for later use in
-    #           passing events up the chain.
     def __init__(self, parent, id = -1, value = "", size = (30,30), style = 0, name = "text", keyHook = None, validator=None):
-
-        #  Call super() for default behavior
         if validator:
             ExpandoTextCtrl.__init__(self, parent, id=id, value=value, size=size, style=style, name=name, validator=validator )
         else:
             ExpandoTextCtrl.__init__(self, parent, id=id, value=value, size=size, style=style, name=name)
 
 
-        self.tree = LetterTree      #  Instantiate a new LetterTree.
-        #  TODO:  make name of word file an argument.
-        self.parent = parent           #  Save parent for later use in passing KeyEvents
-        self.cur = self.tree.rootNode  # self.cur is a short cut placeholder for typing consecutive chars
-                                       # It may be vestigal
-        self.keyHook = keyHook         #  Save the keyHook passed in
+        self.tree = LetterTree 
+        self.parent = parent  
+        self.cur = self.tree.rootNode  
+        self.keyHook = keyHook  
         ExpandoTextCtrl._wrapLine = self._wrapLine
         
 
     def _wrapLine(self, line, dc, width):
-        # Estimate where the control will wrap the lines and
-        # return the count of extra lines needed.
-        # Re writes ExpandoTextCtrl _wrapLine function
         pte = dc.GetPartialTextExtents(line)
         width -= wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X)
         idx = 0
@@ -342,9 +179,7 @@
         while idx < len(pte):
             if line[idx] == ' ': spc = idx
             if pte[idx] - start > width:
-                # we've reached the max width, add a new line
                 count += 1
-                # did we see a space? if so restart the count at that pos
                 if spc != -1:
                     idx = spc + 1
                     spc = -1
@@ -353,31 +188,7 @@
                 idx += 1
         return count
 
-    # findWord subroutine.
-    #
-    # self :  instance of self
-    # insert: index of last char in st
-    # st :    string from insert to the left
-    #
-    # Note:  This implementation is about the third one for this method.  Originally,
-    #        st was an arbitrary string and insert was the point within
-    #        this string to begin looking left.  Since, I finally got it
-    #        to work right as it is around 2 in the morning, I'm not touching it, for now.
-    #
-    # Returns:  String that is the word or "" if none found.  This generally doesn't
-    #           happen, as st usually ends in a letter, which will be returned.
-    #
-    # Purpose:  This function is generally used to figure out the beginning of the
-    #           current word being typed, for later use in a LetterTree.getPrediction()
     def findWord(self, insert, st):
-
-    #  Good luck reading this one.  Basically, I started out with an idea, and fiddled with the
-    #  constants as best I could until it worked.  It's not a piece of work of which I'm too
-    #  proud.  Basically, it's intent is to check each character to the left until it finds one
-    #  that isn't a letter.  If it finds such a character, it stops and returns the slice
-    #  from that point to insert.  Otherwise, it returns the whole thing, due to begin being
-    #  initialized to 0
-
         begin = 0
         for offset in range(insert - 1):
             if st[-(offset + 2)] not in string.ascii_letters:
@@ -385,210 +196,96 @@
                 break
         return st[begin:insert]
 
-
-    # OnChar subroutine.
-    #
-    # self :  instance of self
-    # event:  a GetKeyCode object
-    #
-    # Returns:  None
-    #
-    # Purpose:  This function is the key event handler for predTextCtrl.  It handles what it
-    #           needs to and passes the event on to it's parent's OnChar method.
     def OnChar(self,event):
 
-        #  Before we do anything, call the keyHook handler, if not None
-        #    This is currently used to implement the typing/not_typing messages in a manner that
-        #         doesn't place the code here.  Maybe I should reconsider that.  :)
         if(self.keyHook):
-            if self.keyHook(event) == 1:   #  if the passed in keyHook routine returns a one, it wants no predictive behavior
+            if self.keyHook(event) == 1: 
                 self.parent.OnChar(event)
                 return
-
-        #  This bit converts the GetKeyCode() return (int) to a char if it's in a certain range
         asciiKey = ""
         if (event.GetKeyCode() < 256) and (event.GetKeyCode() > 19):
             asciiKey = chr(event.GetKeyCode())
-
-        if asciiKey == "":                              #  If we didn't convert it to a char, then process based on the int GetKeyCodes
-            if  event.GetKeyCode() == wx.WXK_TAB:       #  We want to hook tabs to allow the user to signify acceptance of a
-                                                        #  predicted word.
-                #  Handle Tab key
-                fromPos = toPos = 0                     # get the current selection range
+        if asciiKey == "":  
+            if  event.GetKeyCode() == wx.WXK_TAB: 
+                fromPos = toPos = 0 
                 (fromPos,toPos) = self.GetSelection()
-                if (toPos - fromPos) == 0:              # if there is no selection, pass tab on
+                if (toPos - fromPos) == 0:  
                     self.parent.OnChar(event)
                     return
-                else:                                      #  This means at least one char is selected
-                    self.SetInsertionPoint(toPos)          #  move the insertion point to the end of the selection
-                    self.SetSelection(toPos,toPos)         #  and set the selection to no chars
-                                                           #  The prediction, if any, had been inserted into the text earlier, so
-                                                           #  moving the insertion point to the spot directly afterwards is
-                                                           #  equivalent to acceptance.  Without this, the next typed key would
-                                                           #  clobber the prediction.
-
-                    return                                 #  Don't pass tab on in this case
+                else:   
+                    self.SetInsertionPoint(toPos)  
+                    self.SetSelection(toPos,toPos) 
+                    return
 
-            elif event.GetKeyCode() == wx.WXK_RETURN:      #  We want to hook returns, so that we can update the word list
-                st = self.GetValue()                       #  Grab the text from the control
-                newSt = ""                                 #  Init a buffer
-                #  This block of code, by popular demand, changes the behavior of the control to ignore any prediction that
-                #  hasn't been "accepted" when the enter key is struck.
-                (startSel,endSel) = self.GetSelection()    #  get the curren selection
-
-                #
-                # Start update
-                # Changed the following to allow for more friendly behavior in
-                # a multilined predTextCtrl.
-                #
-                # front = st[:startSel]                      #  Slice off the text to the front of where we are
-                # back = st[endSel:]                         #  Slice off the text to the end from where we are
-                # st = front + back                          #  This expression creates a string that get rid 
-                                                             #  of any selected text.
-                # self.SetValue(st)
-
+            elif event.GetKeyCode() == wx.WXK_RETURN: 
+                st = self.GetValue() 
+                newSt = "" 
+                (startSel,endSel) = self.GetSelection() 
                 self.Remove( startSel, endSel )
                 st = string.strip( self.GetValue() )
-                #
-                # End update
-                #
-
-                #  this loop will walk through every character in st and add it to
-                #  newSt if it's a letter.  If it's not a letter, (e.g. a comma or
-                #  hyphen) a space is added to newSt in it's place.
                 for ch in st:
                     if ch not in string.ascii_letters:
                         newSt += " "
                     else:
                         newSt += ch
-                #  Now that we've got a string of just letter sequences (words) and spaces
-                #  split it and to a LetterTree.incWord on the lowercase version of it.
-                #  Reminder:  incWord will increment the priority of existing words and add
-                #  new ones
                 for aWord in string.split(newSt):
                     self.tree.incWord(string.lower(aWord))
-                self.parent.OnChar(event) #  Now that all of the words are added, pass the event and return
+                self.parent.OnChar(event)
                 return
 
-            #  We want to capture the right arrow key to fix a slight UI bug that occurs when one right arrows
-            #  out of a selection.  I set the InsertionPoint to the beginning of the selection.  When the default
-            #  right arrow event occurs, the selection goes away, but the cursor is in an unexpected location.
-            #  This snippet fixes this behavior and then passes on the event.
             elif event.GetKeyCode() == wx.WXK_RIGHT:
                 (startSel,endSel) = self.GetSelection()
                 self.SetInsertionPoint(endSel)
                 self.parent.OnChar(event)
                 return
 
-            #  Ditto as wx.WXK_RIGHT, but for completeness sake
             elif event.GetKeyCode() == wx.WXK_LEFT:
                 (startSel,endSel) = self.GetSelection()
                 self.SetInsertionPoint(startSel)
                 self.parent.OnChar(event)
                 return
             else:
-                #   Handle any other non-ascii events by calling parent's OnChar()
-                self.parent.OnChar(event)     #Call super.OnChar to get default behavior
+
+                self.parent.OnChar(event) 
                 return
         elif asciiKey in string.ascii_letters:
-           #  This is the real meat and potatoes of predTextCtrl.  This is where most of the
-           #  wx.TextCtrl logic is changed.
-            (startSel,endSel) = self.GetSelection()                 #  get the curren selection
-            st = self.GetValue()                                    #  and the text in the control
-            front = st[:startSel]                                   #  Slice off the text to the front of where we are
-            back = st[endSel:]                                      #  Slice off the text to the end from where we are
-            st = front + asciiKey + back                            #  This expression creates a string that will insert the
-                                                                    #  typed character (asciiKey is generated at the
-                                                                    #  beginning of OnChar()) into the text.  If there
-                                                                    #  was text selected, that text will not be part
-                                                                    #  of the new string, due to the way front and back
-                                                                    #  were sliced.
+            (startSel,endSel) = self.GetSelection() 
+            st = self.GetValue() 
+            front = st[:startSel]
+            back = st[endSel:]  
+            st = front + asciiKey + back
+            insert = startSel + 1   
+            curWord = ""   
+            if (len(back) == 0) or (back[0] not in string.ascii_letters):
 
-            insert = startSel + 1                                   #  creates an int that denotes where the new InsertionPoint
-                                                                    #  should be.
-            curWord = ""                                            #  Assume there's a problem with finding the curWord
-            if (len(back) == 0) or (back[0] not in string.ascii_letters): #  We should only insert a prediction if we are typing
-                                                                    #  at the end of a word, not in the middle.  There are
-                                                                    #  three cases: we are typing at the end of the string or
-                                                                    #  we are typing in the middle of the string and the next
-                                                                    #  char is NOT a letter or we are typing in the middle of the
-                                                                    #  string and the next char IS a letter.  Only the former two
-                                                                    #  cases denote that we should make a prediction
-                                                                    #  Note:  The order of the two logical clauses here is important!
-                                                                    #         If len(back) == 0, then the expression back[0] will
-                                                                    #         blow up with an out of bounds array subscript.  Luckily
-                                                                    #         the or operator is a short-circuit operator and in this
-                                                                    #         case will only evaluate back[0] if len(back) != 0, in
-                                                                    #         which we're safely in bounds.
+                curWord = self.findWord(insert,front + asciiKey) 
+            else: 
+                self.parent.OnChar(event)
+                return
 
-                curWord = self.findWord(insert,front + asciiKey)    #  Now that we know we're supposed to make a prediction,
-                                                                    #  let's find what word root to use in our prediction.
-                                                                    #  Note:  This is using the confusing findWord method.  I
-                                                                    #         send it insert and the text from the beginning
-                                                                    #         of the text through the key just entered.  This is
-                                                                    #         NOT the original usage, but it does work.  See
-                                                                    #         findWord() for more details.
-
-            else:                                                   #  Here, we've found we're in the middle of a word, so we're
-                                                                    #  going to call the parent's event handler.
+            if curWord == "":  
                 self.parent.OnChar(event)
                 return
 
-            if curWord == "":                                       #  Here, we do a quick check to make sure we have a good root
-                                                                    #  word.  If not, allow the default thing to happen.  Of course,
-                                                                    #  now that I'm documenting this, it occurs to me to wonder why
-                                                                    #  I didn't do the same thing I just talked about.  Hmmmmmm.
-
-                self.parent.OnChar(event)                           # we're done here
+            self.cur = self.tree.findWordNode(string.lower(curWord[:-1])) 
+            if self.cur is None:
+                self.parent.OnChar(event)  
                 return
-
-            self.cur = self.tree.findWordNode(string.lower(curWord[:-1]))  #  Still with me?  We're almost done.  At this point, we
-                                                                           #  need to convert our word string to a Letter node,
-                                                                           #  because that's what getPrediction expects.  Notice
-                                                                           #  that we're feeding in the string with the last
-                                                                           #  char sliced off.  For developmentally historical
-                                                                           #  reasons, getPrediction wants the node just before
-                                                                           #  the typed character and the typed char separately.
-
-
-            if self.cur is None:
-                self.parent.OnChar(event)                                  # if there's no word or no match, we're done
-                return
-
-
-            # get the prediction
-            predictText = self.tree.getPrediction(string.lower(asciiKey),self.cur)     #  This is the big prediction, as noted above
-                                                                                       #  Note the use of string.lower() because we
-                                                                                       #  keep the word list in all lower case,but we
-                                                                                       #  want to be able to match any capitalization
+            predictText = self.tree.getPrediction(string.lower(asciiKey),self.cur) 
 
             if predictText == "":
-                self.parent.OnChar(event)                                              # if there's no prediction, we're done
+                self.parent.OnChar(event)  
                 return
-
-            #  And now for the big finale.  We're going to take the string st
-            #  we created earlier and insert the prediction right after the
-            #  newly typed character.
-            front = st[:insert]                                 #  Grab a new front from st
-            back = st[insert:]                                  #  Grab a new back
-
-            st = front + predictText + back                     #  Insert the prediction
+            front = st[:insert] 
+            back = st[insert:]
 
-            self.SetValue(st)                                   #  Now, overwrite the controls text with the new text
-            self.SetInsertionPoint(insert)                      #  Set the proper insertion point, directly behind the
-                                                                #  newly typed character and directly in front of the
-                                                                #  predicted text.
+            st = front + predictText + back 
+            self.SetValue(st)   
+            self.SetInsertionPoint(insert) 
+            self.SetSelection(insert,insert+len(predictText))
+            return   
+        else:
 
-            self.SetSelection(insert,insert+len(predictText))   #  Very important!  Set the selection to encompass the predicted
-                                                                #  text.  This way, the user can ignore the prediction by simply
-                                                                #  continuing to type.  Remember, if the user wants the prediction
-                                                                #  s/he must strike the tab key at this point.  Of course, one could
-                                                                #  just use the right arrow key as well, but that's not as easy to
-                                                                #  reach.
+            self.parent.OnChar(event) 
+            return
 
-            return                                              #  Done!  Do NOT pass the event on at this point, because it's all done.
-        else:
-            #   Handle every other non-letter ascii (e.g. semicolon) by passing the event on.
-            self.parent.OnChar(event)     #Call super.OnChar to get default behavior
-            return
-#  End of class predTextCtrl!
--- a/orpg/tools/pubsub.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/pubsub.py	Sat Jun 12 03:50:37 2010 -0500
@@ -24,7 +24,7 @@
 
 :Author:      Oliver Schoenborn
 :Since:       Apr 2004
-:Version:     $Id: pubsub.py,v 1.8 2006/06/11 00:12:59 RD Exp $
+:Version:     $Id: pubsub.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 :Copyright:   \(c) 2004 Oliver Schoenborn
 :License:     wxWidgets
 """
--- a/orpg/tools/rgbhex.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/rgbhex.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: rgbhex.py,v 1.10 2007/02/19 16:33:20 digitalxero Exp $
+#   $Id: rgbhex.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: rgb to hex utility
 
--- a/orpg/tools/scriptkit.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/scriptkit.py	Sat Jun 12 03:50:37 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: scriptkit.py,v 1.15 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: scriptkit.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Class that contains convenience methods for various operations.  Was created with the purpose
 #       of exposing a simple API to users of an as yet uncreated scripting interface.
@@ -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 <em>will</em> be labeled unless autolabel is
--- a/orpg/tools/server_probe.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/server_probe.py	Sat Jun 12 03:50:37 2010 -0500
@@ -23,7 +23,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: server_probe.py,v 1.10 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: server_probe.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This is a periodic maintenance script for removing
 # Unresponsive servers from the meta list.
--- a/orpg/tools/settings.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/settings.py	Sat Jun 12 03:50:37 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 = '<tab '
         if tabtype == 'text': tab_xml += 'name="' + tabname + '" type="text" />'
         else: tab_xml += 'name="' + tabname + '" type="' + tabtype + '"></tab>'
-        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()
--- a/orpg/tools/toolBars.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/toolBars.py	Sat Jun 12 03:50:37 2010 -0500
@@ -25,7 +25,7 @@
 #
 #
 
-__version__ = "$Id: toolBars.py,v 1.13 2006/11/04 21:24:22 digitalxero Exp $"
+__version__ = "$Id: toolBars.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
--- a/orpg/tools/validate.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/validate.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,11 +1,3 @@
-# file: config_files.py
-#
-# Author: Todd Faris (Snowdog)
-# Date:   5/10/2005
-#
-# Misc. config file service methods
-#
-
 from orpg.dirpath import dir_struct
 import os
 from orpg.orpgCore import component
--- a/plugins/bcg/tok_dialogs.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,531 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/min_dialogs.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: min_dialogs.py,v 1.27 2006/11/13 02:23:16 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-
-##-----------------------------
-## token List Panel
-##-----------------------------
-
-from tokens import *
-
-class min_list_panel(wx.Dialog):
-
-    def __init__(self, parent,layers, log, pos =(-1,-1)):
-        wx.Dialog.__init__(self,  parent,-1, log,pos = (-1,-1), size = (785,175), style=wx.RESIZE_BORDER)
-        listID = wx.NewId()
-        self.parent = parent
-        self.min = layers['tokens'].tokens
-        self.grid = layers['grid']
-        self.layers = layers
-        self.listID = listID
-        list_sizer = wx.BoxSizer(wx.VERTICAL)
-        self.list_sizer = list_sizer
-        listctrl = wx.ListCtrl(self, listID, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
-        self.listctrl = listctrl
-        self.Centre(wx.BOTH)
-        self.log = log
-        self.list_sizer.Add(self.listctrl,1,wx.EXPAND)
-        self.listctrl.InsertColumn(0,"POS    ")
-        self.listctrl.InsertColumn(0,"LOCKED")
-        self.listctrl.InsertColumn(0,"HEADING")
-        self.listctrl.InsertColumn(0,"FACING")
-        self.listctrl.InsertColumn(0,"LABEL")
-        self.listctrl.InsertColumn(0,"PATH")
-        self.listctrl.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(2, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(4, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(5, wx.LIST_AUTOSIZE_USEHEADER)
-        self.list_sizer.Add(wx.Button(self, wx.ID_OK, "DONE"),0,wx.ALIGN_CENTER)
-        self.refresh()
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-        self.listctrl.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick, id=listID)
-        self.listctrl.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
-        self.listctrl.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-        self.SetSizer(self.list_sizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-    def OnRightClick(self,event):
-        if self.listctrl.GetSelectedItemCount() > 0:
-            menu = wx.Menu()
-            lPopupID1 = wx.NewId()
-            lPopupID2 = wx.NewId()
-            lPopupID3 = wx.NewId()
-            menu.Append(lPopupID1, "&Edit")
-            menu.Append(lPopupID2, "&Delete")
-            menu.Append(lPopupID3, "To &Gametree")
-            self.Bind(wx.EVT_MENU, self.onEdit, id=lPopupID1)
-            self.Bind(wx.EVT_MENU, self.onDelete, id=lPopupID2)
-            self.Bind(wx.EVT_MENU, self.onToGametree, id=lPopupID3)
-            self.PopupMenu(menu, cmpPoint(self.x, self.y))
-            menu.Destroy()
-        event.Skip()
-
-    def refresh(self):
-        self.SetMinSize((600,175));
-        for m in self.min:
-            self.listctrl.InsertStringItem(self.min.index(m),self.min[self.min.index(m)].path)
-            self.listctrl.SetStringItem(self.min.index(m),1,self.min[self.min.index(m)].label)
-            self.listctrl.SetStringItem(self.min.index(m),2,`self.min[self.min.index(m)].heading`)
-            #self.listctrl.SetStringItem(self.min.index(m),3,`self.min[self.min.index(m)].face`)
-            self.listctrl.SetStringItem(self.min.index(m),4,`self.min[self.min.index(m)].locked`)
-            self.listctrl.SetStringItem(self.min.index(m),5,`self.min[self.min.index(m)].pos`)
-            oldcolumnwidth = self.listctrl.GetColumnWidth(0)
-            self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-            if oldcolumnwidth < self.listctrl.GetColumnWidth(0): self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-            else: self.listctrl.SetColumnWidth(0, oldcolumnwidth)
-        self.list_sizer=self.list_sizer
-
-    def onEdit(self,event):
-        min_list = []
-        min_index = []
-        loop_count = 0
-        item =-1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            min_list.append(self.min[item])
-            min_index.append(item-loop_count+1)
-        if len(min_list) > 0: dlg = min_list_edit_dialog(self.parent,min_index, min_list,self.layers)
-        if dlg.ShowModal() == wx.ID_OK: pass
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def onDelete(self,event):
-        loop_count = 0
-        item = -1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            self.layers["tokens"].del_token(self.min[item-loop_count+1])
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def onToGametree(self,event):
-        min_list = []
-        min_index = []
-        loop_count = 0
-        item =-1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            min_list.append(self.min[item])
-            min_index.append(item-loop_count+1)
-        if len(min_list) > 0:
-            for sel_rmin in min_list:
-             #############
-                min_xml = sel_rmin.toxml(action="new")
-                node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
-
-                if sel_rmin.label: node_begin += sel_rmin.label + "'"
-                else: node_begin += "Unnamed token'"
-
-                node_begin += ">"
-                gametree = component.get('tree')
-                node_xml = node_begin + min_xml + '</nodehandler>'
-                print "Sending this XML to insert_xml:" + node_xml
-                gametree.insert_xml(node_xml)
-             #############
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def OnRightDown(self,event):
-        self.x = event.GetX()
-        self.y = event.GetY()
-        event.Skip()
-
-    def on_ok(self,evt):
-        self.EndModal(wx.ID_OK)
-
-class min_list_edit_dialog(wx.Dialog):
-    def __init__(self,parent,min_index, min_list, layers):
-        wx.Dialog.__init__(self,parent,-1,"token List",wx.DefaultPosition,wx.Size(600,530))
-        self.layers = layers
-        grid = layers['grid']
-        min = layers['tokens']
-        self.min_list = min_list
-        self.min_index = min_index
-        self.min = min
-        sizer1 = wx.BoxSizer(wx.VERTICAL)
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.grid = grid
-        editor = min_list_edit_panel(self, min_index, min_list,layers)
-        sizer1.Add(editor, 1, wx.EXPAND)
-        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        sizer1.Add(sizer, 0, wx.EXPAND)
-        self.editor = editor
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-        self.SetSizer(sizer1)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-    def on_revert(self,evt):
-        pass
-
-    def on_ok(self,evt):
-        self.editor.on_ok(self.layers)
-        self.EndModal(wx.ID_OK)
-
-class min_list_edit_panel(wx.Panel):
-    def __init__(self, parent, min_index, min_list,layers):
-        LABEL_COMBO = wx.NewId()
-        PATH_COMBO = wx.NewId()
-        POS_COMB = wx.NewId()
-        MIN_POS = wx.NewId()
-        POS_SPIN = wx.NewId()
-        self.grid = layers['grid']
-        self.min = layers['tokens'].tokens
-        self.min_list = min_list
-        self.min_index = min_index
-        self.layers = layers
-        wx.Panel.__init__(self, parent, -1)
-        self.min=min
-        listsizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"Token list properties"), wx.VERTICAL)
-        labelsizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.labelcheck = wx.CheckBox(self,-1,"Serialize")
-        labelsizer.Add(wx.StaticText(self, -1, "Label:          "), 0, wx.EXPAND)
-        labelsizer.Add(self.labelcheck,wx.ALIGN_RIGHT,wx.EXPAND)
-        listsizer.Add(labelsizer,0, wx.EXPAND)
-        self.labelcombo = wx.ComboBox(self, LABEL_COMBO,"no change",style=wx.CB_DROPDOWN)
-        listsizer.Add(self.labelcombo,0, wx.EXPAND)
-        self.pathcombo = wx.ComboBox(self, PATH_COMBO, "no change",style=wx.CB_DROPDOWN)
-        self.positioncombo = wx.ComboBox(self, POS_COMB, "no change", choices=["no change"], style=wx.CB_READONLY)
-        #self.positioncombo.SetValue(`min_list[0].pos`)
-        self.labelcombo.Append("no change")
-        self.pathcombo.Append("no change")
-        for m in min_list:
-            self.labelcombo.Append(min_list[min_list.index(m)].label)
-            self.pathcombo.Append(min_list[min_list.index(m)].path)
-            self.positioncombo.Append(`min_list[min_list.index(m)].pos`)
-        listsizer.Add(wx.StaticText(self, -1, "Path:"), 0, wx.EXPAND)
-        listsizer.Add(self.pathcombo, 0, wx.EXPAND)
-        listsizer.Add(wx.Size(10,10))
-        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
-            choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
-        self.heading.SetSelection( 9 )
-        listsizer.Add( self.heading, 0, wx.EXPAND )
-        listsizer.Add(wx.Size(10,10))
-
-        ## Remove
-        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
-        #    choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
-        #self.face.SetSelection(9)
-        #listsizer.Add(self.face, 0, wx.EXPAND)
-
-        ###
-        ###Group together locked, Hide, and snap radioboxes in group2 box
-        ###
-        group2 = wx.BoxSizer(wx.HORIZONTAL)
-        self.locked = wx.RadioBox(self, MIN_LOCK, "Lock", 
-            choices=["Don't lock","Lock","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.locked.SetSelection(2)
-        self.hide = wx.RadioBox(self, MIN_HIDE, "Hide", 
-            choices=["Don't hide", "Hide", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.hide.SetSelection(2)
-        self.snap = wx.RadioBox(self,MIN_ALIGN,"Snap",
-            choices=["Center","Top left","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.snap.SetSelection(2)
-        group2.Add(self.locked, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        group2.Add(self.hide, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        group2.Add(self.snap, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        listsizer.Add(group2,0,0)
-        ###
-        ###Group together the postion radiobox and the and its selection elements
-        ###
-        xpos = int(min_list[0].pos[0])
-        #xpos = int(`min_list[0].pos`[1:`min_list[0].pos`.index(',')])
-        ypos = int(min_list[0].pos[1])
-        #ypos = int(`min_list[0].pos`[`min_list[0].pos`.rfind(',')+1:len(`min_list[0].pos`)-1])
-        self.scx = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
-        self.scx.SetRange(0,self.grid.return_grid()[0])
-        self.scx.SetValue(xpos)
-        self.scy = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
-        self.scy.SetRange(0,self.grid.return_grid()[1])
-        self.scy.SetValue(1)
-        self.scy.SetValue(ypos)
-        positionbox = wx.BoxSizer(wx.HORIZONTAL)
-        self.poschoice = wx.RadioBox(self,MIN_POS,"Position",
-            choices=["Manual", "Existing", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.poschoice.SetSelection(2)
-        positionbox.Add(self.poschoice,0,0)
-        ###
-        ### group together choices under position choice boxsizer
-        ###
-        poschoicebox = wx.BoxSizer(wx.VERTICAL)
-            ###
-            ### spinbox contains the x and y spinctrls
-            ###
-        spinbox = wx.BoxSizer(wx.HORIZONTAL)
-        group2.Add(positionbox,0, wx.EXPAND)
-        xpos = wx.StaticText(self, -1,"XPOS:  ")
-        spinbox.Add(xpos,0, 0)
-        spinbox.Add(self.scx, 0, 0)
-        ypos = wx.StaticText(self, -1,"YPOS:  ")
-        spinbox.Add(ypos,0, 0)
-        spinbox.Add(self.scy, 0, 0)
-        poschoicebox.Add(wx.Size(0,15))
-        poschoicebox.Add(spinbox,0,0)
-        ###
-        ### kludge is just a way to horizontaly position text.  .Add doesn't seem to work.
-        ###
-        kluge = wx.BoxSizer(wx.HORIZONTAL)
-        klugetext = wx.StaticText(self, -1, "            ")
-        kluge.Add(klugetext,0,0)
-        kluge.Add(self.positioncombo,0,0)
-        poschoicebox.Add(wx.Size(0,1))
-        poschoicebox.Add(kluge,0,0)
-        positionbox.Add(poschoicebox,0,0)
-        listsizer.Add(positionbox,0, 0)
-        self.listsizer = listsizer
-        #self.outline = wx.StaticBox(self,-1,"token list properties")
-        #listsizer.Add(self.outline,0, wx.EXPAND)
-        self.SetSizer(listsizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-        self.Bind(wx.EVT_SPINCTRL, self.on_spin, id=POS_SPIN)
-        self.Bind(wx.EVT_TEXT, self.on_combo_box, id=POS_COMB)
-        #self.Bind(wx.EVT_SIZE, self.on_size)
-        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
-
-    def on_ok(self,min):
-        self.min = min
-        for m in self.min_list:
-            if self.hide.GetSelection() !=2: m.hide = self.hide.GetSelection()
-            if self.heading.GetSelection() !=9: m.heading = self.heading.GetSelection()
-            #if self.face.GetSelection() !=9: m.face = self.face.GetSelection()
-            if self.locked.GetSelection() !=2: m.locked = self.locked.GetSelection()
-            if self.snap.GetSelection() !=2: m.snap_to_align = self.snap.GetSelection()
-            if self.labelcombo.GetValue() != "no change":
-                m.label = self.labelcombo.GetValue()
-                if self.labelcheck.GetValue(): m.label += " " + `self.layers['tokens'].next_serial()`
-            if self.pathcombo.GetValue() != "no change":
-                path = self.pathcombo.GetValue()
-                image = self.evaluate(path)
-                if str(image[1]) != '-1':
-                    m.path = image[0]
-                    m.bmp = image[1]
-                else:
-                    image[-1] = -1
-                    while image[1] == -1:
-                        image = 0
-                        self.dlg = wx.TextEntryDialog(self, 
-                            'You entered an invalid URL for the image path.  Please Enter a valid URL or cancel to leave the old url unchanged')
-                        if self.dlg.ShowModal() == wx.ID_OK:
-                            path = self.dlg.GetValue()
-                            image = self.evaluate(path)
-                            if image[1] != -1:
-                                m.path = image[0]
-                                m.bmp = image[1]
-                            self.dlg.Destroy()
-                        else: break
-            if self.poschoice.GetSelection() !=2:
-                if self.poschoice.GetSelection() == 0: m.pos = cmpPoint(self.scx.GetValue(),self.scy.GetValue())
-                else:
-                    pos = self.positioncombo.GetValue()
-                    m.pos = cmpPoint(int(`pos`[2:`pos`.index(",")]),int(`pos`[`pos`.rfind(',')+1:len(`pos`)-2]))
-        self.layers["tokens"].canvas.send_map_data()
-
-    def evaluate(self, ckpath):
-        path = []
-        if ckpath[:7] != "http://": ckpath = "http://" + ckpath
-        path = self.check_path(ckpath)
-        return [ckpath, path]
-
-    def check_path(self, path):
-        if ImageHandler.Cache.has_key(path): return ImageHandler.Cache[path]
-        img = ImageHandler.directLoad(path)
-        if img is None: return -1
-        return img
-
-    def on_text(self,evt):
-        id=evt.GetId()
-
-    def on_spin(self,evt):
-        self.poschoice.SetSelection(0)
-
-    def on_combo_box(self,evt):
-        self.poschoice.SetSelection(1)
-
-    def on_radio_box(self,evt):
-        id=evt.GetId()
-        index = evt.GetInt()
-
-    def on_size(self,evt):
-        s = self.GetClientSizeTuple()
-        self.listsizer.SetDimension(20,20,s[0]-40,s[1]-40)
-        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
-
-##-----------------------------
-## token Prop Panel
-##-----------------------------
-
-MIN_LABEL = wx.NewId()
-MIN_HEADING = wx.NewId()
-MIN_FACE = wx.NewId()
-MIN_HIDE = wx.NewId()
-MIN_LOCK = wx.NewId()
-MIN_ALIGN = wx.NewId()
-wxID_MIN_WIDTH = wx.NewId()
-wxID_MIN_HEIGHT = wx.NewId()
-wxID_MIN_SCALING = wx.NewId()
-
-class min_edit_panel(wx.Panel):
-    def __init__(self, parent, min):
-        wx.Panel.__init__(self, parent, -1)
-        self.min = min
-        sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"token"), wx.VERTICAL)
-        sizerSize = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.label = wx.TextCtrl(self, MIN_LABEL, min.label)
-        sizer.Add(wx.StaticText(self, -1, "Label:"), 0, wx.EXPAND)
-        sizer.Add(self.label, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
-            choices=["None","N","NE",
-                     "E","SE","S",
-                     "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
-        self.heading.SetSelection(min.heading)
-        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
-        #    choices=["None","N","NE",
-        #             "E","SE","S",
-        #             "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
-        #self.face.SetSelection(min.face)
-        self.locked = wx.CheckBox(self, MIN_LOCK, " Lock")
-        self.locked.SetValue(min.locked)
-        self.hide = wx.CheckBox(self, MIN_HIDE, " Hide")
-        self.hide.SetValue(min.hide)
-        sizer.Add(self.heading, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        #sizer.Add(self.face, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        #
-        #image resizing
-        #
-        self.min_width_old_value = str(self.min.bmp.GetWidth())
-        self.min_width = wx.TextCtrl(self, wxID_MIN_WIDTH, self.min_width_old_value)
-        sizerSize.Add(wx.StaticText(self, -1, "Width: "), 0, wx.ALIGN_CENTER)
-        sizerSize.Add(self.min_width, 1, wx.EXPAND)
-        sizerSize.Add(wx.Size(20, 25))
-
-        #TODO:keep in mind that self.min is a local copy???
-        self.min_height_old_value = str(self.min.bmp.GetHeight())
-        self.min_height = wx.TextCtrl(self, wxID_MIN_HEIGHT, self.min_height_old_value)
-        sizerSize.Add(wx.StaticText(self, -1, "Height: "),0,wx.ALIGN_CENTER)
-        sizerSize.Add(self.min_height, 1, wx.EXPAND)
-        self.min_scaling = wx.CheckBox(self, wxID_MIN_SCALING, "Lock scaling")
-        self.min_scaling.SetValue(True)
-        sizerSize.Add(self.min_scaling, 1, wx.EXPAND)
-        sizer.Add(sizerSize, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10, 10))
-
-        # Now, add the last items on in their own sizer
-        hSizer.Add(self.locked, 0, wx.EXPAND)
-        hSizer.Add(wx.Size(10,10))
-        hSizer.Add(self.hide, 0, wx.EXPAND)
-
-        # Add the hSizer to the main sizer
-        sizer.Add( hSizer )
-        self.sizer = sizer
-        self.SetSizer(self.sizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-        #self.Bind(wx.EVT_SIZE, self.on_size)
-        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
-        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_WIDTH)
-        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_HEIGHT)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
-        #self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
-
-    def on_scaling(self, evt):
-        if self.min_scaling.GetValue() == False: return
-        elif self.min_width.GetValue() and wxID_MIN_WIDTH == evt.GetId() and self.min_width.GetInsertionPoint():
-            self.min_height.SetValue(str(int((float(self.min_width.GetValue()) / float(self.min_width_old_value)) * float(self.min_height_old_value))) )
-        elif self.min_height.GetValue() and wxID_MIN_HEIGHT == evt.GetId() and self.min_height.GetInsertionPoint():
-            self.min_width.SetValue(str(int((float(self.min_height.GetValue()) / float(self.min_height_old_value)) * float(self.min_width_old_value))) )
-
-    def update_min(self):
-        self.min.set_min_props(self.heading.GetSelection(),
-                               #self.face.GetSelection(),
-                               self.label.GetValue(),
-                               self.locked.GetValue(),
-                               self.hide.GetValue(),
-                               self.min_width.GetValue(),
-                               self.min_height.GetValue())
-
-    def on_radio_box(self,evt):
-        id = evt.GetId()
-        index = evt.GetInt()
-
-    def on_text(self,evt):
-        id = evt.GetId()
-
-    def on_size(self,evt):
-        s = self.GetClientSizeTuple()
-        self.sizer.SetDimension(20,20,s[0]-40,s[1]-40)
-        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
-
-class min_edit_dialog(wx.Dialog):
-    def __init__(self,parent,min):
-        #520,265
-        wx.Dialog.__init__(self,parent,-1,"token",wx.DefaultPosition,wx.Size(520,350))
-        (w,h) = self.GetClientSizeTuple()
-        mastersizer = wx.BoxSizer(wx.VERTICAL)
-        editor = min_edit_panel(self,min)
-        #editor.SetDimensions(0,0,w,h-25)
-        self.editor = editor
-        mastersizer.Add(editor, 1, wx.EXPAND)
-        mastersizer.Add(wx.Size(10,10))
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        #sizer.SetDimension(0,h-25,w,25)
-        mastersizer.Add(sizer, 0, wx.EXPAND)
-        self.SetSizer(mastersizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-
-    def on_ok(self,evt):
-        self.editor.update_min()
-        self.EndModal(wx.ID_OK)
--- a/plugins/bcg/token_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,883 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/whiteboard_hander.py
-# Author: OpenRPG Team
-# Maintainer:
-# Version:
-#   $Id: token_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $
-#
-# Description: Token layer handler; derived from token Layer handler
-#
-__version__ = "$Id: token_handler.py,v 1.43 2007/12/07 20:39:50 madmathlabs Exp $"
-
-from orpg.mapper.base_handler import *
-from tok_dialogs import *
-import thread
-import time
-import mimetypes
-import urllib
-import xml.dom.minidom as minidom
-import wx
-
-## rewrite Grid
-from orpg.mapper.grid import GRID_RECTANGLE
-from orpg.mapper.grid import GRID_HEXAGON
-from orpg.mapper.grid import GRID_ISOMETRIC
-import os
-
-from orpg.tools.orpg_settings import settings
-
-## Jesus H! No Face, rotate!
-TOK_ROT_LEFT = wx.NewId()
-ROT_LEFT_45 = wx.NewId()
-LABEL_TOOL = wx.NewId()
-LAYER_TOOL = wx.NewId()
-TOK_LIST_TOOL = wx.NewId()
-TOK_TOOL = wx.NewId()
-TOK_URL = wx.NewId()
-SERIAL_TOOL = wx.NewId()
-TOK_MOVE = wx.NewId()
-TOK_REMOVE = wx.NewId()
-TOK_PROP_DLG = wx.NewId()
-TOK_FACING_NONE = wx.NewId()
-TOK_FACING_MATCH = wx.NewId()
-TOK_FACING_EAST = wx.NewId()
-TOK_FACING_WEST = wx.NewId()
-TOK_FACING_NORTH = wx.NewId()
-TOK_FACING_SOUTH = wx.NewId()
-TOK_FACING_NORTHEAST = wx.NewId()
-TOK_FACING_SOUTHEAST = wx.NewId()
-TOK_FACING_SOUTHWEST = wx.NewId()
-TOK_FACING_NORTHWEST = wx.NewId()
-TOK_HEADING_NONE = wx.NewId()
-TOK_HEADING_MATCH = wx.NewId()
-TOK_HEADING_EAST = wx.NewId()
-TOK_HEADING_WEST = wx.NewId()
-TOK_HEADING_NORTH = wx.NewId()
-TOK_HEADING_SOUTH = wx.NewId()
-TOK_HEADING_NORTHEAST = wx.NewId()
-TOK_HEADING_SOUTHEAST = wx.NewId()
-TOK_HEADING_SOUTHWEST = wx.NewId()
-TOK_HEADING_NORTHWEST = wx.NewId()
-TOK_HEADING_SUBMENU = wx.NewId()
-TOK_FACING_SUBMENU = wx.NewId()
-TOK_ALIGN_SUBMENU = wx.NewId()
-TOK_ALIGN_GRID_CENTER = wx.NewId()
-TOK_ALIGN_GRID_TL = wx.NewId()
-TOK_TITLE_HACK = wx.NewId()
-TOK_TO_GAMETREE = wx.NewId()
-TOK_BACK_ONE = wx.NewId()
-TOK_FORWARD_ONE = wx.NewId()
-TOK_TO_BACK = wx.NewId()
-TOK_TO_FRONT = wx.NewId()
-TOK_LOCK_BACK = wx.NewId()
-TOK_LOCK_FRONT = wx.NewId()
-TOK_FRONTBACK_UNLOCK = wx.NewId()
-TOK_ZORDER_SUBMENU = wx.NewId()
-TOK_SHOW_HIDE = wx.NewId()
-TOK_LOCK_UNLOCK = wx.NewId()
-MAP_REFRESH_MINI_URLS = wx.NewId()
-
-class myFileDropTarget(wx.FileDropTarget):
-    def __init__(self, handler):
-        wx.FileDropTarget.__init__(self)
-        self.m_handler = handler
-    def OnDropFiles(self, x, y, filenames):
-        self.m_handler.on_drop_files(x, y, filenames)
-
-class token_handler(base_layer_handler):
-
-    def __init__(self, parent, id, canvas):
-        self.sel_min = None
-        self.auto_label = 1
-        self.use_serial = 1
-        self.auto_label_cb = None
-        self.canvas = canvas
-        self.settings = settings
-        self.mini_rclick_menu_extra_items = {}
-        self.background_rclick_menu_extra_items = {}
-        base_layer_handler.__init__(self, parent, id, canvas)
-        # id is the index of the last good menu choice or 'None'
-        # if the last menu was left without making a choice
-        # should be -1 at other times to prevent events overlapping
-        self.lastMenuChoice = None
-        self.drag_mini = None
-        self.tooltip_delay_miliseconds = 500
-        self.tooltip_timer = wx.CallLater(self.tooltip_delay_miliseconds, self.on_tooltip_timer)
-        self.tooltip_timer.Stop()
-        dt = myFileDropTarget(self)
-        self.canvas.SetDropTarget(dt)
-        #wxInitAllImageHandlers()
-
-    def build_ctrls(self):
-        base_layer_handler.build_ctrls(self)
-        # add controls in reverse order! (unless you want them after the default tools)
-        self.auto_label_cb = wx.CheckBox(self, wx.ID_ANY, ' Auto Label ', (-1,-1),(-1,-1))
-        self.auto_label_cb.SetValue(self.auto_label)
-        self.min_url = wx.ComboBox(self, wx.ID_ANY, "http://", style=wx.CB_DROPDOWN | wx.CB_SORT)
-        self.localBrowse = wx.Button(self, wx.ID_ANY, 'Browse', style=wx.BU_EXACTFIT)
-        minilist = createMaskedButton( self, dir_struct["icon"]+'questionhead.gif', 'Edit token properties', wx.ID_ANY)
-        miniadd = wx.Button(self, wx.ID_OK, "Add Token", style=wx.BU_EXACTFIT)
-        self.sizer.Add(self.auto_label_cb,0,wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(self.min_url, 1, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(miniadd, 0, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(self.localBrowse, 0, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(minilist, 0, wx.ALIGN_CENTER)
-        self.Bind(wx.EVT_BUTTON, self.on_min_list, minilist)
-        self.Bind(wx.EVT_BUTTON, self.on_token, miniadd)
-        self.Bind(wx.EVT_BUTTON, self.on_browse, self.localBrowse)
-        self.Bind(wx.EVT_CHECKBOX, self.on_label, self.auto_label_cb)
-
-    def on_browse(self, evt):
-        if not self.role_is_gm_or_player(): return
-        dlg = wx.FileDialog(None, "Select a Token to load", dir_struct["user"]+'webfiles/', 
-            wildcard="Image files (*.bmp, *.gif, *.jpg, *.png)|*.bmp;*.gif;*.jpg;*.png", style=wx.OPEN)
-        if not dlg.ShowModal() == wx.ID_OK:
-            dlg.Destroy()
-            return
-        file = open(dlg.GetPath(), "rb")
-        imgdata = file.read()
-        file.close()
-        filename = dlg.GetFilename()
-        (imgtype,j) = mimetypes.guess_type(filename)
-        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
-
-        ## Removal of Remote Server?
-        if self.settings.get_setting('LocalorRemote') == 'Remote':
-            # make the new mini appear in top left of current viewable map
-            dc = wx.ClientDC(self.canvas)
-            self.canvas.PrepareDC(dc)
-            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-            x = dc.DeviceToLogicalX(0)
-            y = dc.DeviceToLogicalY(0)
-            thread.start_new_thread(self.canvas.layers['token'].upload, 
-                                    (postdata, dlg.GetPath()), {'pos':cmpPoint(x,y)})
-        else:
-            try: min_url = component.get("cherrypy") + filename
-            except: return #chat.InfoPost('CherryPy is not started!')
-            min_url = dlg.GetDirectory().replace(dir_struct["user"]+'webfiles' + os.sep, 
-                component.get("cherrypy")) + '/' + filename
-            # build url
-            if min_url == "" or min_url == "http://": return
-            if min_url[:7] != "http://": min_url = "http://" + min_url
-            # make label
-            if self.auto_label and min_url[-4:-3] == '.':
-                start = min_url.rfind("/") + 1
-                min_label = min_url[start:len(min_url)-4]
-                if self.use_serial: min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
-            else: min_label = ""
-            if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
-            try:
-                id = 'mini-' + self.canvas.frame.session.get_next_id()
-                # make the new mini appear in top left of current viewable map
-                dc = wx.ClientDC(self.canvas)
-                self.canvas.PrepareDC(dc)
-                dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-                x = dc.DeviceToLogicalX(0)
-                y = dc.DeviceToLogicalY(0)
-                self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
-            except:
-                # When there is an exception here, we should be decrementing the serial_number for reuse!!
-                unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
-                dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
-                dlg.ShowModal()
-                dlg.Destroy()
-                self.canvas.layers['token'].rollback_serial()
-            self.canvas.send_map_data()
-            self.canvas.Refresh(False)
-
-
-    def build_menu(self,label = "Token"):
-        ## Menu Changes: Rotate
-        ## Menu into Component
-        ## Remove To GameTree option
-        base_layer_handler.build_menu(self,label)
-        self.main_menu.AppendSeparator()
-        self.main_menu.Append(LABEL_TOOL,"&Auto label","",1)
-        self.main_menu.Check(LABEL_TOOL,self.auto_label)
-        self.main_menu.Append(SERIAL_TOOL,"&Number minis","",1)
-        self.main_menu.Check(SERIAL_TOOL, self.use_serial)
-        self.main_menu.Append(MAP_REFRESH_MINI_URLS,"&Refresh tokens")       #  Add the menu item
-        self.main_menu.AppendSeparator()
-        self.main_menu.Append(TOK_MOVE, "Move")
-        self.canvas.Bind(wx.EVT_MENU, self.on_map_board_menu_item, id=MAP_REFRESH_MINI_URLS) #  Set the handler
-        self.canvas.Bind(wx.EVT_MENU, self.on_label, id=LABEL_TOOL)
-        self.canvas.Bind(wx.EVT_MENU, self.on_serial, id=SERIAL_TOOL)
-        # build token menu
-        self.min_menu = wx.Menu()
-        # Rectangles and hexagons require slightly different menus because of
-        # facing and heading possibilities.
-
-        rot_left = wx.Menu()
-        rot_left_45 = rot_left.Append(-1, '45*')
-        self.canvas.Bind(wx.EVT_MENU, self.rot_left_45, rot_left_45)
-        rot_right = wx.Menu()
-
-        rot_right_45 = rot_right.Append(-1, '45*')
-        self.canvas.Bind(wx.EVT_MENU, self.rot_right_45, rot_right_45)
-        ## Replace with Rotate. Left - Right, 45 - 90 degress.
-        """
-        face_menu = wx.Menu()
-        face_menu.Append(TOK_FACING_NONE,"&None")
-        face_menu.Append(TOK_FACING_NORTH,"&North")
-        face_menu.Append(TOK_FACING_NORTHEAST,"Northeast")
-        face_menu.Append(TOK_FACING_EAST,"East")
-        face_menu.Append(TOK_FACING_SOUTHEAST,"Southeast")
-        face_menu.Append(TOK_FACING_SOUTH,"&South")
-        face_menu.Append(TOK_FACING_SOUTHWEST,"Southwest")
-        face_menu.Append(TOK_FACING_WEST,"West")
-        face_menu.Append(TOK_FACING_NORTHWEST,"Northwest")
-        """
-        ###
-
-        heading_menu = wx.Menu()
-        heading_menu.Append(TOK_HEADING_NONE,"&None")
-        heading_menu.Append(TOK_HEADING_NORTH,"&North")
-        heading_menu.Append(TOK_HEADING_NORTHEAST,"Northeast")
-        heading_menu.Append(TOK_HEADING_EAST,"East")
-        heading_menu.Append(TOK_HEADING_SOUTHEAST,"Southeast")
-        heading_menu.Append(TOK_HEADING_SOUTH,"&South")
-        heading_menu.Append(TOK_HEADING_SOUTHWEST,"Southwest")
-        heading_menu.Append(TOK_HEADING_WEST,"West")
-        heading_menu.Append(TOK_HEADING_NORTHWEST,"Northwest")
-
-        align_menu = wx.Menu()
-        align_menu.Append(TOK_ALIGN_GRID_CENTER,"&Center")
-        align_menu.Append(TOK_ALIGN_GRID_TL,"&Top-Left")
-        #  This is a hack to simulate a menu title, due to problem in Linux
-        if wx.Platform == '__WXMSW__': self.min_menu.SetTitle(label)
-        else:
-            self.min_menu.Append(TOK_TITLE_HACK,label)
-            self.min_menu.AppendSeparator()
-        self.min_menu.Append(TOK_SHOW_HIDE,"Show / Hide")
-        self.min_menu.Append(TOK_LOCK_UNLOCK, "Lock / Unlock")
-        self.min_menu.Append(TOK_REMOVE,"&Remove")
-
-        ##Remove
-        #self.min_menu.Append(TOK_TO_GAMETREE,"To &Gametree")
-        ###
-
-        self.min_menu.AppendMenu(TOK_HEADING_SUBMENU,"Set &Heading",heading_menu)
-
-        ##Remove
-        self.min_menu.AppendMenu(TOK_ROT_LEFT,"&Rotate Left",rot_left)
-        self.min_menu.AppendMenu(wx.ID_ANY,"&Rotate Right",rot_right)
-        ###
-
-        self.min_menu.AppendMenu(TOK_ALIGN_SUBMENU,"Snap-to &Alignment",align_menu)
-        self.min_menu.AppendSeparator()
-        zorder_menu = wx.Menu()
-        zorder_menu.Append(TOK_BACK_ONE,"Back one")
-        zorder_menu.Append(TOK_FORWARD_ONE,"Forward one")
-        zorder_menu.Append(TOK_TO_BACK,"To back")
-        zorder_menu.Append(TOK_TO_FRONT,"To front")
-        zorder_menu.AppendSeparator()
-        zorder_menu.Append(TOK_LOCK_BACK,"Lock to back")
-        zorder_menu.Append(TOK_LOCK_FRONT,"Lock to front")
-        zorder_menu.Append(TOK_FRONTBACK_UNLOCK,"Unlock Front/Back")
-        self.min_menu.AppendMenu(TOK_ZORDER_SUBMENU, "Token Z-Order",zorder_menu)
-        #self.min_menu.Append(TOK_LOCK,"&Lock")
-        self.min_menu.AppendSeparator()
-        self.min_menu.Append(TOK_PROP_DLG,"&Properties")
-
-
-        #self.min_menu.AppendSeparator()
-        #self.min_menu.Append(TOK_MOVE, "Move")
-
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_MOVE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_SHOW_HIDE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_UNLOCK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_REMOVE)
-
-        ##Remove
-        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_GAMETREE)
-        ###
-
-        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_PROP_DLG)
-
-        ##Remove
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_EAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_WEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHWEST)
-        ###
-
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_EAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_WEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_CENTER)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_TL)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_BACK_ONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FORWARD_ONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_BACK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_FRONT)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_BACK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_FRONT)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FRONTBACK_UNLOCK)
-        ######### add plugin added menu items #########
-        if len(self.mini_rclick_menu_extra_items)>0:
-            self.min_menu.AppendSeparator()
-            for item in self.mini_rclick_menu_extra_items.items(): self.min_menu.Append(item[1], item[0])
-        if len(self.background_rclick_menu_extra_items)>0:
-            self.main_menu.AppendSeparator()
-            for item in self.background_rclick_menu_extra_items.items():
-                self.main_menu.Append(item[1], item[0])
-
-    def do_min_menu(self,pos):
-        self.canvas.PopupMenu(self.min_menu,pos)
-
-    def rot_left_45(self, evt):
-        #self.sel_rmin.rotate += 0.785
-        self.sel_rmin.rotate += 1.046
-        #component.get('drawn')[self.sel_rmin] = False
-
-    def rot_right_45(self, evt):
-        #self.sel_rmin.rotate -= 0.785
-        self.sel_rmin.rotate -= 1.046
-
-    def do_min_select_menu(self, min_list, pos):
-        # to prevent another event being processed
-        self.lastMenuChoice = None
-        self.min_select_menu = wx.Menu()
-        self.min_select_menu.SetTitle("Select Token")
-        loop_count = 1
-        try:
-            for m in min_list:
-                # Either use the token label for the selection list
-                if m.label: self.min_select_menu.Append(loop_count, m.label)
-                # Or use part of the images filename as an identifier
-                else:
-                    string_split = string.split(m.path,"/",)
-                    last_string = string_split[len(string_split)-1]
-                    self.min_select_menu.Append(loop_count, 'Unlabeled - ' + last_string[:len(last_string)-4])
-                self.canvas.Bind(wx.EVT_MENU, self.min_selected, id=loop_count)
-                loop_count += 1
-            self.canvas.PopupMenu(self.min_select_menu,pos)
-        except: pass
-
-    def min_selected(self,evt):
-        # this is the callback function for the menu that is used to choose
-        # between minis when you right click, left click or left double click
-        # on a stack of two or more
-        self.canvas.Refresh(False)
-        self.canvas.send_map_data()
-        self.lastMenuChoice = evt.GetId()-1
-
-    def on_min_menu_item(self,evt):
-        id = evt.GetId()
-        if id == TOK_MOVE:
-            if self.sel_min:
-                self.moveSelectedMini(self.last_rclick_pos)
-                self.deselectAndRefresh()
-            return
-        elif id == TOK_REMOVE: self.canvas.layers['token'].del_token(self.sel_rmin)
-
-        ##Remove
-        elif id == TOK_TO_GAMETREE:
-            min_xml = self.sel_rmin.toxml(action="new")
-            node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
-            if self.sel_rmin.label: node_begin += self.sel_rmin.label + "'"
-            else:  node_begin += "Unnamed token'"
-            node_begin += ">"
-	    gametree = component.get('tree')
-            node_xml = node_begin + min_xml + '</nodehandler>'
-            #print "Sending this XML to insert_xml:" + node_xml
-            gametree.insert_xml(str(node_xml))
-
-        elif id == TOK_SHOW_HIDE:
-            if self.sel_rmin.hide:  self.sel_rmin.hide = 0
-            else: self.sel_rmin.hide = 1
-        elif id == TOK_LOCK_UNLOCK:
-            if self.sel_rmin.locked: self.sel_rmin.locked = False
-            else: self.sel_rmin.locked = True
-            if self.sel_rmin == self.sel_min:
-                # when we lock / unlock the selected mini make sure it isn't still selected
-                # or it might easily get moved by accident and be hard to move back
-                self.sel_min.selected = False
-                self.sel_min.isUpdated = True
-                self.sel_min = None
-	recycle_bin = {TOK_HEADING_NONE: FACE_NONE, TOK_HEADING_NORTH: FACE_NORTH, 
-        TOK_HEADING_NORTHWEST: FACE_NORTHWEST, TOK_HEADING_NORTHEAST: FACE_NORTHEAST, 
-        TOK_HEADING_EAST: FACE_EAST, TOK_HEADING_SOUTHEAST: FACE_SOUTHEAST, TOK_HEADING_SOUTHWEST: FACE_SOUTHWEST, 
-        TOK_HEADING_SOUTH: FACE_SOUTH, TOK_HEADING_WEST: FACE_WEST}
-	if recycle_bin.has_key(id):
-	    self.sel_rmin.heading = recycle_bin[id]
-	    del recycle_bin
-	recycle_bin = {TOK_FACING_NONE: FACE_NONE, TOK_FACING_NORTH: FACE_NORTH, 
-        TOK_FACING_NORTHWEST: FACE_NORTHWEST, TOK_FACING_NORTHEAST: FACE_NORTHEAST, 
-        TOK_FACING_EAST: FACE_EAST, TOK_FACING_SOUTHEAST: FACE_SOUTHEAST, TOK_FACING_SOUTHWEST: FACE_SOUTHWEST, 
-        TOK_FACING_SOUTH: FACE_SOUTH, TOK_FACING_WEST: FACE_WEST}
-	if recycle_bin.has_key(id):
-	    self.sel_rmin.face = recycle_bin[id]
-	    del recycle_bin
-        elif id == TOK_ALIGN_GRID_CENTER: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_CENTER
-        elif id == TOK_ALIGN_GRID_TL: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_TL
-        elif id == TOK_PROP_DLG:
-            old_lock_value = self.sel_rmin.locked
-            dlg = min_edit_dialog(self.canvas.frame.GetParent(),self.sel_rmin)
-            if dlg.ShowModal() == wx.ID_OK:
-                if self.sel_rmin == self.sel_min and self.sel_rmin.locked != old_lock_value:
-                    # when we lock / unlock the selected mini make sure it isn't still selected
-                    # or it might easily get moved by accident and be hard to move back
-                    self.sel_min.selected = False
-                    self.sel_min.isUpdated = True
-                    self.sel_min = None
-                self.canvas.Refresh(False)
-                self.canvas.send_map_data()
-                return
-
-        elif id == TOK_BACK_ONE:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-		##   print "old z-order = " + str(oldz)
-                self.sel_rmin.zorder -= 1
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_FORWARD_ONE:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-	    ##  print "old z-order = " + str(oldz)
-            self.sel_rmin.zorder += 1
-
-            #  Re-collapse to normalize
-            #  Note:  only one update (with the final values) will be sent
-            self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_TO_FRONT:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-	    ##  print "old z-order = " + str(oldz)
-                #  The new z-order will be one more than the last index
-                newz = len(self.canvas.layers['token'].token)
-	    ##  print "new z-order = " + str(newz)
-                self.sel_rmin.zorder = newz
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_TO_BACK:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-	    ##  print "old z-order = " + str(oldz)
-
-                #  Since 0 is the lowest in a normalized order, be one less
-                newz = -1
-	    ##  print "new z-order = " + str(newz)
-                self.sel_rmin.zorder = newz
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_FRONTBACK_UNLOCK:
-            #print "Unlocked/ unstickified..."
-            if self.sel_rmin.zorder == TOK_STICKY_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK + 1
-            elif self.sel_rmin.zorder == TOK_STICKY_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT - 1
-        elif id == TOK_LOCK_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK
-        elif id == TOK_LOCK_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT
-        # Pretty much, we always want to refresh when we go through here
-        # This helps us remove the redundant self.Refresh() on EVERY menu event
-        # that we process above.
-        self.sel_rmin.isUpdated = True
-        self.canvas.Refresh(False)
-        self.canvas.send_map_data()
-
-    def on_token(self, evt):
-        session = self.canvas.frame.session
-        if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER) and (session.use_roles()):
-            self.infoPost("You must be either a player or GM to use the token Layer")
-            return
-        min_url = self.min_url.GetValue()
-        # build url
-        if min_url == "" or min_url == "http://": return
-        if min_url[:7] != "http://" : min_url = "http://" + min_url
-        # make label
-        if self.auto_label and min_url[-4:-3] == '.':
-            start = min_url.rfind("/") + 1
-            min_label = min_url[start:len(min_url)-4]
-            if self.use_serial:
-                min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
-        else: min_label = ""
-        if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
-        try:
-            id = 'mini-' + self.canvas.frame.session.get_next_id()
-            # make the new mini appear in top left of current viewable map
-            dc = wx.ClientDC(self.canvas)
-            self.canvas.PrepareDC(dc)
-            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-            x = dc.DeviceToLogicalX(0)
-            y = dc.DeviceToLogicalY(0)
-            self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
-        except:
-            # When there is an exception here, we should be decrementing the serial_number for reuse!!
-            unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
-            #print unablemsg
-            dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
-            dlg.ShowModal()
-            dlg.Destroy()
-            self.canvas.layers['token'].rollback_serial()
-        self.canvas.send_map_data()
-        self.canvas.Refresh(False)
-        #except Exception, e:
-            #wx.MessageBox(str(e),"token Error")
-
-    def on_label(self,evt):
-        self.auto_label = not self.auto_label
-        self.auto_label_cb.SetValue(self.auto_label)
-        #self.send_map_data()
-        #self.Refresh()
-
-    def on_min_list(self,evt):
-        session = self.canvas.frame.session
-        if (session.my_role() != session.ROLE_GM):
-            self.infoPost("You must be a GM to use this feature")
-            return
-        #d = min_list_panel(self.frame.GetParent(),self.canvas.layers,"token list")
-        d = min_list_panel(self.canvas.frame,self.canvas.layers,"token list")
-        if d.ShowModal() == wx.ID_OK: d.Destroy()
-        self.canvas.Refresh(False)
-
-    def on_serial(self, evt):
-        self.use_serial = not self.use_serial
-
-    def on_map_board_menu_item(self,evt):
-        id = evt.GetId()
-        if id == MAP_REFRESH_MINI_URLS:   # Note: this doesn't change the mini, so no need to update the map
-            for mini in self.canvas.layers['token'].tokens:       #  For all minis
-                mini.set_bmp(ImageHandler.load(mini.path, 'token', mini.id))      #  Reload their bmp member
-            self.canvas.Refresh(False)
-
-####################################################################
-    ## old functions, changed an awful lot
-
-    def on_left_down(self, evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini:
-            deselecting_selected_mini = (mini == self.sel_min) #clicked on the selected mini
-            self.deselectAndRefresh()
-            self.drag_mini = mini
-            if deselecting_selected_mini: return
-            self.sel_min = mini
-            self.sel_min.selected = True
-            self.canvas.Refresh()
-        else:
-            self.drag_mini = None
-            pos = self.getLogicalPosition(evt)
-            self.moveSelectedMini(pos)
-            self.deselectAndRefresh()
-
-    def on_right_down(self, evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        self.last_rclick_pos = self.getLogicalPosition(evt)
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini:
-            self.sel_rmin = mini
-            if self.sel_min: self.min_menu.Enable(TOK_MOVE, True)
-            else: self.min_menu.Enable(TOK_MOVE, False)
-            self.prepare_mini_rclick_menu(evt)
-            self.do_min_menu(evt.GetPosition())
-        else:# pass it on
-            if self.sel_min: self.main_menu.Enable(TOK_MOVE, True)
-            else: self.main_menu.Enable(TOK_MOVE, False)
-            self.prepare_background_rclick_menu(evt)
-            base_layer_handler.on_right_down(self, evt)
-
-####################################################################
-    ## new functions
-
-    def on_drop_files(self, x, y, filepaths):
-        # currently we ignore multiple files
-        filepath = filepaths[0]
-        start1 = filepath.rfind("\\") + 1 # check for both slashes in path to be on the safe side
-        start2 = filepath.rfind("/") + 1
-        if start1 < start2: start1 = start2
-        filename = filepath[start1:]
-        pos = filename.rfind('.')
-        ext = filename[pos:].lower()
-        #ext = filename[-4:].lower()
-        if(ext != ".bmp" and ext != ".gif" and ext != ".jpg" and ext != ".jpeg" and ext != ".png"):
-            self.infoPost("Supported file extensions are: *.bmp, *.gif, *.jpg, *.jpeg, *.png")
-            return
-        file = open(filepath, "rb")
-        imgdata = file.read()
-        file.close()
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        x = dc.DeviceToLogicalX(x)
-        y = dc.DeviceToLogicalY(y)
-        (imgtype,j) = mimetypes.guess_type(filename)
-        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
-        thread.start_new_thread(self.canvas.layers['token'].upload, (postdata, filepath), {'pos':cmpPoint(x,y)})
-
-    def on_tooltip_timer(self, *args):
-        pos = args[0]
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        pos = wx.Point(dc.DeviceToLogicalX(pos.x), dc.DeviceToLogicalY(pos.y))
-        mini_list = self.getMiniListOrSelectedMini(pos)
-        if len(mini_list) > 0:
-            print mini_list
-            tooltip = self.get_mini_tooltip(mini_list); print tooltip
-            self.canvas.SetToolTipString(tooltip)
-        else: self.canvas.SetToolTipString("")
-
-    def on_motion(self,evt):
-        if evt.Dragging() and evt.LeftIsDown():
-            if self.canvas.drag is None and self.drag_mini is not None:
-                drag_bmp = self.drag_mini.bmp
-                if self.drag_mini.width and self.drag_mini.height:
-                    tmp_image = drag_bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.drag_mini.width * self.canvas.layers['grid'].mapscale), 
-                        int(self.drag_mini.height * self.canvas.layers['grid'].mapscale))
-                    tmp_image.ConvertAlphaToMask()
-
-                    ### Should show rotated image when dragging.
-                    if self.drag_mini.rotate != 0 :
-                        tmp_image = tmp_image.Rotate(self.drag_mini.rotate, 
-                                                    (self.drag_mini.width/2, self.drag_mini.height/2))
-
-                    drag_bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(drag_bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    drag_bmp.SetMask(mask)
-                    tmp_image = tmp_image.ConvertToGreyscale()
-                    self.drag_mini.gray = True
-                    self.drag_mini.isUpdated = True
-                    def refresh():
-                        self.canvas.drag.Hide()
-                        self.canvas.Refresh(False)
-                    wx.CallAfter(refresh)
-                self.canvas.drag = wx.DragImage(drag_bmp)
-                self.drag_offset = self.getLogicalPosition(evt)- self.drag_mini.pos
-                self.canvas.drag.BeginDrag((int(self.drag_offset.x * self.canvas.layers['grid'].mapscale), 
-                    int(self.drag_offset.y * self.canvas.layers['grid'].mapscale)), self.canvas, False)
-            elif self.canvas.drag is not None:
-                self.canvas.drag.Move(evt.GetPosition())
-                self.canvas.drag.Show()
-        # reset tool tip timer
-        self.canvas.SetToolTipString("")
-        self.tooltip_timer.Restart(self.tooltip_delay_miliseconds, evt.GetPosition())
-
-    def on_left_up(self,evt):
-        if self.canvas.drag:
-            self.canvas.drag.Hide()
-            self.canvas.drag.EndDrag()
-            self.canvas.drag = None
-            pos = self.getLogicalPosition(evt)
-            pos = pos - self.drag_offset
-            if self.canvas.layers['grid'].snap:
-                nudge = int(self.canvas.layers['grid'].unit_size/2)
-                if self.canvas.layers['grid'].mode != GRID_ISOMETRIC:
-                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
-                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2),int(self.drag_mini.bmp.GetHeight()/2))
-                    else: pos = pos + (nudge, nudge)
-                else:# GRID_ISOMETRIC
-                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
-                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2), self.drag_mini.bmp.GetHeight())
-                    else: pass # no nudge for the isomorphic / top-left
-            self.sel_min = self.drag_mini
-            # check to see if the mouse is inside the window still
-            w = self.canvas.GetClientSizeTuple() # this is the window size, minus any scrollbars
-            p = evt.GetPosition() # compare the window size, w with the non-logical position
-            c = self.canvas.size # this is the grid size, compare with the logical position, pos
-            # both are [width, height]
-            if p.x>=0 and pos.x<c[0] and p.x<w[0] and p.y>=0 and pos.y<c[1] and p.y<w[1]:
-                self.moveSelectedMini(pos)
-            self.sel_min.gray = False
-            self.sel_min.selected = False
-            self.sel_min.isUpdated = True
-            self.canvas.Refresh(False)
-            self.canvas.send_map_data()
-            self.sel_min = None
-        self.drag_mini = None
-
-    def on_left_dclick(self,evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini: self.on_mini_dclick(evt, mini)
-        else: base_layer_handler.on_left_dclick(self, evt)
-
-
-####################################################################
-    ## hook functions (although with python you can override any of the functions)
-
-    def prepare_mini_rclick_menu(self, evt):
-        # override the entire right-click on a mini menu
-        pass
-
-    def prepare_background_rclick_menu(self, evt):
-        # override the entire right-click on the map menu
-        pass
-
-    def get_mini_tooltip(self, mini_list):
-        # override to create a tooltip
-        return ""
-
-    def on_mini_dclick(self, evt, mini):
-        # do something after the mini was left double clicked
-        pass
-
-####################################################################
-    ## easy way to add a single menu item
-
-    def set_mini_rclick_menu_item(self, label, callback_function):
-        # remember you might want to call these at the end of your callback function:
-        # mini_handler.sel_rmin.isUpdated = True
-        # canvas.Refresh(False)
-        # canvas.send_map_data()
-        if callback_function == None: del self.mini_rclick_menu_extra_items[label]
-        else:
-            if not self.mini_rclick_menu_extra_items.has_key(label):
-                self.mini_rclick_menu_extra_items[label]=wx.NewId()
-            menu_id = self.mini_rclick_menu_extra_items[label]
-            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
-        self.build_menu()
-
-    def set_background_rclick_menu_item(self, label, callback_function):
-        if callback_function == None: del self.background_rclick_menu_extra_items[label]
-        else:
-            if not self.background_rclick_menu_extra_items.has_key(label):
-                self.background_rclick_menu_extra_items[label]=wx.NewId()
-            menu_id = self.background_rclick_menu_extra_items[label]
-            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
-        self.build_menu()
-
-
-####################################################################
-    ## helper functions
-
-    def infoPost(self, message):
-        component.get("chat").InfoPost(message)
-
-    def role_is_gm_or_player(self):
-        session = self.canvas.frame.session
-        if (session.my_role() <> session.ROLE_GM) and (session.my_role() <> session.ROLE_PLAYER) and (session.use_roles()):
-            self.infoPost("You must be either a player or GM to use the token Layer")
-            return False
-        return True
-
-    def role_is_gm(self):
-        session = self.canvas.frame.session
-        if (session.my_role() <> session.ROLE_GM) and (session.use_roles()): return False
-        return True
-
-    def alreadyDealingWithMenu(self):
-        return self.lastMenuChoice is not None
-
-    def getLastMenuChoice(self):
-        choice = self.lastMenuChoice
-        self.lastMenuChoice = None
-        return choice
-
-    def getLogicalPosition(self, evt):
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        pos = evt.GetLogicalPosition(dc)
-        return pos
-
-    def getMiniListOrSelectedMini(self, pos, include_locked=False):
-        if self.sel_min and self.sel_min.hit_test(pos):
-            # clicked on the selected mini - assume that is the intended target
-            # and don't give a choice of it and any other minis stacked with it
-            mini_list = []
-            mini_list.append(self.sel_min)
-            return mini_list
-        mini_list = self.canvas.layers['token'].find_token(pos, (not include_locked))
-        if mini_list: return mini_list
-        mini_list = []
-        return mini_list
-
-    def deselectAndRefresh(self):
-        if self.sel_min:
-            self.sel_min.selected = False
-            self.sel_min.isUpdated = True
-            self.canvas.Refresh(False)
-            self.canvas.send_map_data()
-            self.sel_min = None
-
-    def moveSelectedMini(self, pos):
-        if self.sel_min: self.moveMini(pos, self.sel_min)
-
-    def moveMini(self, pos, mini):
-        grid = self.canvas.layers['grid']
-        mini.pos = grid.get_snapped_to_pos(pos, mini.snap_to_align, mini.bmp.GetWidth(), mini.bmp.GetHeight())
-
-    def find_mini(self, evt, include_locked):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        pos = self.getLogicalPosition(evt)
-        mini_list = self.getMiniListOrSelectedMini(pos, include_locked)
-        mini = None
-        if len(mini_list) > 1:
-            try: self.do_min_select_menu(mini_list, evt.GetPosition())
-            except: pass
-            choice = self.getLastMenuChoice()
-            if choice == None: return None # left menu without making a choice, eg by clicking outside menu
-            mini = mini_list[choice]
-        elif len(mini_list) == 1: mini = mini_list[0]
-        return mini
-
--- a/plugins/bcg/tokens.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,600 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/tokens.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: tokens.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-#
-__version__ = "$Id: tokens.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
-
-from orpg.mapper.base import *
-import thread
-import time
-import urllib
-import os.path
-
-from orpg.tools.orpg_settings import settings
-
-MIN_STICKY_BACK = -0XFFFFFF
-MIN_STICKY_FRONT = 0xFFFFFF
-
-##----------------------------------------
-##  token object
-##----------------------------------------
-
-FACE_NONE = 0
-FACE_NORTH = 1
-FACE_NORTHEAST = 2
-FACE_EAST = 3
-FACE_SOUTHEAST = 4
-FACE_SOUTH = 5
-FACE_SOUTHWEST = 6
-FACE_WEST = 7
-FACE_NORTHWEST = 8
-SNAPTO_ALIGN_CENTER = 0
-SNAPTO_ALIGN_TL = 1
-
-def cmp_zorder(first,second):
-    f = first.zorder
-    s = second.zorder
-    if f == None: f = 0
-    if s == None: s = 0
-    if f == s: value = 0
-    elif f < s: value = -1
-    else: value = 1
-    return value
-
-class BmpToken:
-    def __init__(self, id,path, bmp, pos=cmpPoint(0,0), 
-                heading=FACE_NONE, rotate=0, label="", 
-                locked=False, hide=False, snap_to_align=SNAPTO_ALIGN_CENTER, 
-                zorder=0, width=0, height=0, log=None, local=False, localPath='', localTime=-1):
-        self.heading = heading
-        self.rotate = rotate
-        self.label = label
-        self.path = path
-        self.bmp = bmp
-        self.pos = pos
-        self.selected = False
-        self.locked = locked
-        self.snap_to_align = snap_to_align
-        self.hide = hide
-        self.id = id
-        self.zorder = zorder
-        self.left = 0
-        self.local = local
-        self.localPath = localPath
-        self.localTime = localTime
-        if not width: self.width = 0
-        else: self.width = width
-        if not height: self.height = 0
-        else: self.height = height
-        self.right = bmp.GetWidth()
-        self.top = 0
-        self.bottom = bmp.GetHeight()
-        self.isUpdated = False
-        self.gray = False
-        self.drawn = {}
-
-    def __del__(self):
-        del self.bmp
-        self.bmp = None
-
-    def set_bmp(self, bmp):
-        self.bmp = bmp
-
-    def set_min_props(self, heading=FACE_NONE, rotate=0, label="", locked=False, hide=False, width=0, height=0):
-        self.heading = heading
-        self.rotate = rotate
-        self.label = label
-        if locked: self.locked = True
-        else: self.locked = False
-        if hide: self.hide = True
-        else: self.hide = False
-        self.width = int(width)
-        self.height = int(height)
-        self.isUpdated = True
-
-    def hit_test(self, pt):
-        rect = self.get_rect()
-        result = None
-        result = rect.InsideXY(pt.x, pt.y)
-        return result
-
-    def get_rect(self):
-        ret = wx.Rect(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-        return ret
-
-    def draw(self, dc, mini_layer, op=wx.COPY):
-        if isinstance(self.bmp, tuple):
-            self.bmp = wx.ImageFromMime(self.bmp[1], self.bmp[2]).ConvertToBitmap()
-        if self.bmp != None and self.bmp.Ok():
-            # check if hidden and GM: we outline the mini in grey (little bit smaller than the actual size)
-            # and write the label in the center of the mini
-            if self.hide and mini_layer.canvas.frame.session.my_role() == mini_layer.canvas.frame.session.ROLE_GM:
-                # set the width and height of the image
-                if self.width and self.height:
-                    tmp_image = self.bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.width), int(self.height))
-                    tmp_image.ConvertAlphaToMask()
-                    self.bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    self.bmp.SetMask(mask)
-                    del tmp_image
-                    del mask
-                self.left = 0
-                self.right = self.bmp.GetWidth()
-                self.top = 0
-                self.bottom = self.bmp.GetHeight()
-                # grey outline
-                graypen = wx.Pen("gray", 1, wx.DOT)
-                dc.SetPen(graypen)
-                dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                #if width or height < 20 then offset = 1
-                if self.bmp.GetWidth() <= 20: xoffset = 1
-                else: xoffset = 5
-                if self.bmp.GetHeight() <= 20: yoffset = 1
-                else: yoffset = 5
-                dc.DrawRectangle(self.pos.x + xoffset, 
-                    self.pos.y + yoffset, self.bmp.GetWidth() - (xoffset * 2), 
-                    self.bmp.GetHeight() - (yoffset * 2))
-                dc.SetBrush(wx.NullBrush)
-                dc.SetPen(wx.NullPen)
-                ## draw label in the center of the mini
-                label = mini_layer.get_mini_label(self)
-                if len(label):
-                    dc.SetTextForeground(wx.RED)
-                    (textWidth,textHeight) = dc.GetTextExtent(label)
-                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
-                    y = self.pos.y + (self.bmp.GetHeight() / 2)
-                    dc.SetPen(wx.GREY_PEN)
-                    dc.SetBrush(wx.LIGHT_GREY_BRUSH)
-                    dc.DrawRectangle(x, y, textWidth+2, textHeight+2)
-                    if (textWidth+2 > self.right):
-                        self.right += int((textWidth+2-self.right)/2)+1
-                        self.left -= int((textWidth+2-self.right)/2)+1
-                    self.bottom = y+textHeight+2-self.pos.y
-                    dc.SetPen(wx.NullPen)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.DrawText(label, x+1, y+1)
-
-                #selected outline
-                if self.selected:
-                    dc.SetPen(wx.RED_PEN)
-                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                return True
-            elif self.hide: return True
-
-            else:
-                # set the width and height of the image
-                bmp = self.bmp
-                if self.width and self.height:
-                    tmp_image = self.bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.width), int(self.height))
-                    tmp_image.ConvertAlphaToMask()
-                    self.bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    self.bmp.SetMask(mask)
-                    if self.gray:
-                        tmp_image = tmp_image.ConvertToGreyscale()
-                        bmp = tmp_image.ConvertToBitmap()
-                    else: bmp = self.bmp
-
-                if self.rotate != 0:
-                    x = bmp.GetWidth(); print x
-                    y = bmp.GetHeight(); print y
-                    img = bmp.ConvertToImage()
-                    img = img.Rotate(self.rotate, (3, 80), True)
-                    img.ConvertAlphaToMask()
-
-                    bmp = img.ConvertToBitmap()
-                    mask = wx.Mask(bmp, wx.Colour(img.GetMaskRed(), 
-                        img.GetMaskGreen(), img.GetMaskBlue()))
-                    bmp.SetMask(mask)
-
-                dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
-                component.get('drawn')[bmp] = True
-                self.left = 0
-                self.right = self.bmp.GetWidth()
-                self.top = 0
-                self.bottom = self.bmp.GetHeight()
-
-                # Draw the heading if needed
-                if self.heading:
-                    x_adjust = 0
-                    y_adjust = 4
-                    x_half = self.bmp.GetWidth()/2
-                    y_half = self.bmp.GetHeight()/2
-                    x_quarter = self.bmp.GetWidth()/4
-                    y_quarter = self.bmp.GetHeight()/4
-                    x_3quarter = x_quarter*3
-                    y_3quarter = y_quarter*3
-                    x_full = self.bmp.GetWidth()
-                    y_full = self.bmp.GetHeight()
-                    x_center = self.pos.x + x_half
-                    y_center = self.pos.y + y_half
-                    # Remember, the pen/brush must be a different color than the
-                    # facing marker!!!!  We'll use black/cyan for starters.
-                    # Also notice that we will draw the heading on top of the
-                    # larger facing marker.
-                    dc.SetPen(wx.BLACK_PEN)
-                    dc.SetBrush(wx.CYAN_BRUSH)
-                    triangle = []
-
-                    # Figure out which direction to draw the marker!!
-                    if self.heading == FACE_NORTH:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
-                        triangle.append(cmpPoint(x_center, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
-                    elif self.heading ==  FACE_SOUTH:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
-                        triangle.append(cmpPoint(x_center, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
-                    elif self.heading == FACE_NORTHEAST:
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
-                    elif self.heading == FACE_EAST:
-                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center ))
-                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
-                    elif self.heading == FACE_SOUTHEAST:
-                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
-                    elif self.heading == FACE_SOUTHWEST:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
-                    elif self.heading == FACE_WEST:
-                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center ))
-                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
-                    elif self.heading == FACE_NORTHWEST:
-                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
-                    dc.DrawPolygon(triangle)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                #selected outline
-                if self.selected:
-                    dc.SetPen(wx.RED_PEN)
-                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                # draw label
-                label = mini_layer.get_mini_label(self)
-                if len(label):
-                    dc.SetTextForeground(wx.RED)
-                    (textWidth,textHeight) = dc.GetTextExtent(label)
-                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
-                    y = self.pos.y + self.bmp.GetHeight() + 6
-                    dc.SetPen(wx.WHITE_PEN)
-                    dc.SetBrush(wx.WHITE_BRUSH)
-                    dc.DrawRectangle(x,y,textWidth+2,textHeight+2)
-                    if (textWidth+2 > self.right):
-                        self.right += int((textWidth+2-self.right)/2)+1
-                        self.left -= int((textWidth+2-self.right)/2)+1
-                    self.bottom = y+textHeight+2-self.pos.y
-                    dc.SetPen(wx.NullPen)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.DrawText(label,x+1,y+1)
-                self.top-=5
-                self.bottom+=5
-                self.left-=5
-                self.right+=5
-                return True
-        else: return False
-
-    def toxml(self, action="update"):
-        if action == "del":
-            xml_str = "<token action='del' id='" + self.id + "'/>"
-            return xml_str
-        xml_str = "<token"
-        xml_str += " action='" + action + "'"
-        xml_str += " label='" + self.label + "'"
-        xml_str+= " id='" + self.id + "'"
-        if self.pos != None:
-            xml_str += " posx='" + str(self.pos.x) + "'"
-            xml_str += " posy='" + str(self.pos.y) + "'"
-        if self.heading != None: xml_str += " heading='" + str(self.heading) + "'"
-        if self.rotate != None: xml_str += " rotate='" + str(self.rotate) + "'"
-        if self.path != None: xml_str += " path='" + urllib.quote(self.path).replace('%3A', ':') + "'"
-        if self.locked: xml_str += "  locked='1'"
-        else: xml_str += "  locked='0'"
-        if self.hide: xml_str += " hide='1'"
-        else: xml_str += " hide='0'"
-        if self.snap_to_align != None: xml_str += " align='" + str(self.snap_to_align) + "'"
-        if self.id != None: xml_str += " zorder='" + str(self.zorder) + "'"
-        if self.width != None: xml_str += " width='" + str(self.width) + "'"
-        if self.height != None: xml_str += " height='" + str(self.height) + "'"
-        if self.local:
-            xml_str += ' local="' + str(self.local) + '"'
-            xml_str += ' localPath="' + str(urllib.quote(self.localPath).replace('%3A', ':')) + '"'
-            xml_str += ' localTime="' + str(self.localTime) + '"'
-        xml_str += " />"
-        if (action == "update" and self.isUpdated) or action == "new":
-            self.isUpdated = False
-            return xml_str
-        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("rotate"):
-            self.rotate = int(xml_dom.getAttribute("rotate"))
-        if xml_dom.hasAttribute("path"):
-            self.path = urllib.unquote(xml_dom.getAttribute("path"))
-            self.set_bmp(ImageHandler.load(self.path, 'token', self.id))
-        if xml_dom.hasAttribute("locked"):
-            if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("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
-            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
-            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"))
-
-##-----------------------------
-## token layer
-##-----------------------------
-class token_layer(layer_base):
-    def __init__(self, canvas):
-        self.canvas = canvas
-        layer_base.__init__(self)
-        self.id = -1 #added.
-        self.tokens = []
-        self.serial_number = 0
-
-        self.drawn = {}
-        component.add('drawn', self.drawn)
-        # Set the font of the labels to be the same as the chat window
-        # only smaller.
-        font_size = int(settings.get_setting('defaultfontsize'))
-        if (font_size >= 10): font_size -= 2
-        self.label_font = wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL,
-                                  False, settings.get_setting('defaultfont'))
-
-    def next_serial(self):
-        self.serial_number += 1
-        return self.serial_number
-
-    def get_next_highest_z(self):
-        z = len(self.tokens)+1
-        return z
-
-    def cleanly_collapse_zorder(self):
-        #  lock the zorder stuff
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        i = 0
-        for mini in sorted_tokens:
-            mini.zorder = i
-            i = i + 1
-        #  unlock the zorder stuff
-
-    def collapse_zorder(self):
-        #  lock the zorder stuff
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        i = 0
-        for mini in sorted_tokens:
-            if (mini.zorder != MIN_STICKY_BACK) and (mini.zorder != MIN_STICKY_FRONT): mini.zorder = i
-            else: pass
-            i = i + 1
-        #  unlock the zorder stuff
-
-    def rollback_serial(self):
-        self.serial_number -= 1
-
-    def add_token(self, id, path, pos=cmpPoint(0,0), label="", heading=FACE_NONE, 
-            rotate=0, width=0, height=0, local=False, localPath='', localTime=-1):
-        bmp = ImageHandler.load(path, 'token', id)
-        if bmp:
-            mini = BmpToken(id, path, bmp, pos, heading, rotate, label, 
-                zorder=self. get_next_highest_z(), width=width, 
-                height=height, local=local, localPath=localPath, localTime=localTime)
-            self.tokens.append(mini)
-            self.drawn[mini.bmp] = False
-            xml_str = "<map><tokens>"
-            xml_str += mini.toxml("new")
-            xml_str += "</tokens></map>"
-            component.get('session').send(xml_str)
-
-    def get_token_by_id(self, id):
-        for mini in self.tokens:
-            if str(mini.id) == str(id):
-                return mini
-        return None
-
-    def del_token(self, min):
-        xml_str = "<map><tokens>"
-        xml_str += min.toxml("del")
-        xml_str += "</tokens></map>"
-        self.canvas.frame.session.send(xml_str)
-        self.tokens.remove(min)
-        del min
-        self.collapse_zorder()
-
-    def del_all_tokens(self):
-        while len(self.tokens):
-            min = self.tokens.pop()
-            del min
-        self.collapse_zorder()
-
-    def layerDraw(self, dc, topleft, size):
-        dc.SetFont(self.label_font)
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        for m in sorted_tokens:
-            if (m.pos.x>topleft[0]-m.right and
-                m.pos.y>topleft[1]-m.bottom and
-                m.pos.x<topleft[0]+size[0]-m.left and
-                m.pos.y<topleft[1]+size[1]-m.top):
-                """
-                if self.drawn.has_key(m.bmp):
-                    if self.drawn[m.bmp] == True:
-                        dc2 = wx.MemoryDC()
-                        img = m.bmp.ConvertToImage()
-                        bmp = img.ConvertToBitmap()
-
-                        dc2.SelectObject(bmp)
-                        dc.Blit(m.pos.x, m.pos.y, img.GetHeight(), img.GetWidth(), dc2, 0, 0, wx.COPY, True, 0, 0)
-                        del dc2
-                
-                else:
-                """
-                m.draw(dc, self)
-
-    def find_token(self, pt, only_unlocked=False):
-        min_list = []
-        for m in self.tokens:
-            if m.hit_test(pt):
-                if m.hide and self.canvas.frame.session.my_role() != self.canvas.frame.session.ROLE_GM: continue
-                if only_unlocked and not m.locked: min_list.append(m)
-                elif not only_unlocked and m.locked: min_list.append(m)
-                else: continue
-        if len(min_list) > 0:
-            return min_list
-        else: return None
-
-    def layerToXML(self, action="update"):
-        """ format  """
-        minis_string = ""
-        if self.tokens:
-            for m in self.tokens: minis_string += m.toxml(action)
-        if minis_string != '':
-            s = "<tokens"
-            s += " serial='" + str(self.serial_number) + "'"
-            s += ">"
-            s += minis_string
-            s += "</tokens>"
-            return s
-        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()
-        for c in children:
-            action = c.getAttribute("action")
-            id = c.getAttribute('id')
-            if action == "del": 
-                mini = self.get_token_by_id(id)
-                if mini:
-                    self.tokens.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')
-                height = width = heading = rotate = 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('rotate'): rotate = int(c.getAttribute('rotate'))
-                if c.hasAttribute('align'): snap_to_align = int(c.getAttribute('align'))
-                if c.getAttribute('zorder'): zorder = int(c.getAttribute('zorder'))
-                min = BmpToken(id, path, ImageHandler.load(path, 'token', id), pos, heading, 
-                    rotate, label, locked, hide, snap_to_align, zorder, width, height)
-                self.tokens.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'))
-                    local = True
-                    localTime = float(c.getAttribute('localTime'))
-                    if localTime-time.time() <= 144000:
-                        file = open(localPath, "rb")
-                        imgdata = file.read()
-                        file.close()
-                        filename = os.path.split(localPath)
-                        (imgtype,j) = mimetypes.guess_type(filename[1])
-                        postdata = urllib.urlencode({'filename':filename[1], 'imgdata':imgdata, 'imgtype':imgtype})
-                        thread.start_new_thread(self.upload, (postdata, localPath, True))
-                #  collapse the zorder.  If the client behaved well, then nothing should change.
-                #    Otherwise, this will ensure that there's some kind of z-order
-                self.collapse_zorder()
-            else:
-                mini = self.get_token_by_id(id)
-                if mini: mini.takedom(c)
-
-    def upload(self, postdata, filename, modify=False, pos=cmpPoint(0,0)):
-        self.lock.acquire()
-        url = settings.get_setting('ImageServerBaseURL')
-        file = urllib.urlopen(url, postdata)
-        recvdata = file.read()
-        file.close()
-        try:
-            xml_dom = minidom.parseString(recvdata)._get_documentElement()
-            if xml_dom.nodeName == 'path':
-                path = xml_dom.getAttribute('url')
-                path = urllib.unquote(path)
-                if not modify:
-                    start = path.rfind("/") + 1
-                    if self.canvas.parent.layer_handlers[2].auto_label: min_label = path[start:len(path)-4]
-                    else: min_label = ""
-                    id = 'mini-' + self.canvas.frame.session.get_next_id()
-                    self.add_token(id, path, pos=pos, label=min_label, local=True, 
-                        localPath=filename, localTime=time.time())
-                else:
-                    self.tokens[len(self.tokens)-1].local = True
-                    self.tokens[len(self.tokens)-1].localPath = filename
-                    self.tokens[len(self.tokens)-1].localTime = time.time()
-                    self.tokens[len(self.tokens)-1].path = path
-            else:
-                print xml_dom.getAttribute('msg')
-        except Exception, e:
-            print e
-            print recvdata
-        urllib.urlcleanup()
-        self.lock.release()
-####################################################################
-        ## helper function
-
-    def get_mini_label(self, mini):
-        # override this to change the label displayed under each mini (and the label on hidden minis)
-        return mini.label
--- a/plugins/bcg/tokens_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/tokens_msg.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-#
-__version__ = "$Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
-
-from base_msg import *
-
-class mini_msg(map_element_msg_base):
-
-    def __init__(self,reentrant_lock_object = None):
-        self.tagname = "token"   # set this to be for minis.  Tagname gets used in some base class functions.
-        map_element_msg_base.__init__(self,reentrant_lock_object)   # call base class
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element containing only the changes to this mini
-    def standalone_update_text(self,update_id_string):
-        buffer = "<map id='" + update_id_string + "'>"
-        buffer += "<tokens>"
-        buffer += self.get_changed_xml()
-        buffer += "</tokens></map>"
-        return buffer
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element that deletes this mini
-    def standalone_delete_text(self,update_id_string):
-        buffer = None
-        if self._props.has_key("id"):
-            buffer = "<map id='" + update_id_string + "'>"
-            buffer += "<tokens>"
-            buffer += "<token action='del' id='" + self._props("id") + "'/>"
-            buffer += "</tokens></map>"
-        return buffer
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element to add this mini
-    def standalone_add_text(self,update_id_string):
-        buffer = "<map id='" + update_id_string + "'>"
-        buffer += "<tokens>"
-        buffer += self.get_all_xml()
-        buffer += "</tokens></map>"
-        return buffer
-
-    def get_all_xml(self,action="new",output_action=1):
-        return map_element_msg_base.get_all_xml(self,action,output_action)
-
-    def get_changed_xml(self,action="update",output_action=1):
-        return map_element_msg_base.get_changed_xml(self,action,output_action)
-
-class minis_msg(map_element_msg_base):
-
-    def __init__(self,reentrant_lock_object = None):
-        self.tagname = "tokens"
-        map_element_msg_base.__init__(self,reentrant_lock_object)
-
-    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():
-                mini = mini_msg(self.p_lock)
-                try: mini.init_from_dom(c)
-                except Exception, e: print e; continue
-                id = mini.get_prop("id")
-                action = mini.get_prop("action")
-
-                if action == "new": self.children[id] = mini
-                elif action == "del":
-                    if self.children.has_key(id):
-                        self.children[id] = None
-                        del self.children[id]
-
-                elif action == "update":
-                    if self.children.has_key(id):
-                        self.children[id].init_props(mini.get_all_props())
-        else:
-            self.p_lock.release()
-            raise Exception, "Error attempting to initialize a " + self.tagname + " from a non-<" + self.tagname + "/> element"
-        self.p_lock.release()
-
-    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():
-                mini = mini_msg(self.p_lock)
-
-                try: mini.set_from_dom(c)
-                except Exception, e: print e; continue
-                id = mini.get_prop("id")
-                action = mini.get_prop("action")
-                if action == "new": self.children[id] = mini
-                elif action == "del":
-                    if self.children.has_key(id):
-                        self.children[id] = None
-                        del self.children[id]
-                elif action == "update":
-                    if self.children.has_key(id):
-                        self.children[id].set_props(mini.get_all_props())
-        else:
-            self.p_lock.release()
-            raise Exception, "Error attempting to set a " + self.tagname + " from a non-<" + self.tagname + "/> element"
-        self.p_lock.release()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/cherrypy/License.txt	Sat Jun 12 03:50:37 2010 -0500
@@ -0,0 +1,26 @@
+Copyright (c) 2002-2008, CherryPy Team (team@cherrypy.org)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+      this list of conditions and the following disclaimer in the documentation 
+      and/or other materials provided with the distribution.
+    * Neither the name of the CherryPy Team nor the names of its contributors 
+      may be used to endorse or promote products derived from this software 
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
--- a/plugins/xxbcg.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-import os
-import sys
-import orpg.pluginhandler
-from orpg.mapper.map import *
-from orpg.orpgCore import component
-import wx
-
-from orpg.mapper.images import ImageHandler
-from orpg.mapper.whiteboard_handler import *
-from orpg.mapper.background_handler import *
-from orpg.mapper.grid_handler import *
-from orpg.mapper.map_handler import *
-from orpg.mapper.fog_handler import *
-
-from bcg.token_handler import *
-from bcg.tokens import *
-
-
-class Plugin(orpg.pluginhandler.PluginHandler):
-    # Initialization subroutine.
-    #
-    # !self : instance of self
-    # !openrpg : instance of the the base openrpg control
-    def __init__(self, plugindb, parent):
-        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
-
-        # The Following code should be edited to contain the proper information
-        self.name = 'Board / Card Game'
-        self.author = 'Tyler Starke (Prof. Ebral)'
-        self.help = 'Start Here'
-        self.parent = parent
-        #You can set variables below here. Always set them to a blank value in this section. Use plugin_enabled
-        #to set their proper values.
-        self.sample_variable = {}
-
-        self.canvas = component.get('map').canvas ## Obtain MapCanvas
-
-    def plugin_enabled(self):
-        tabs = component.get('map_tabs')
-        layers = component.get('map_layers')
-        map_wnd = component.get('map_wnd')
-        pages = tabs.GetPageCount()
-        self.layers = []
-        while pages:
-            pages -= 1
-            if tabs.GetPageText(pages) != 'Background':
-                if tabs.GetPageText(pages) != 'Whiteboard': 
-                    tabs.RemovePage(pages)
-        #tabs.InsertPage(2, layers[0], 'Tiles') # Removed for testing.
-        map_wnd.handlers[6]=(token_handler(tabs, -1, map_wnd.canvas))
-        tabs.InsertPage(3, map_wnd.handlers[6], 'Tokens')
-
-        ## Re Direct MapCanvas OnPaint event.
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
-        self.canvas.Bind(wx.EVT_PAINT, self.on_paint)
-
-        ## Add to MapCanvas proccessImages
-        self.canvas.Bind(wx.EVT_TIMER, self.processImages, self.canvas.image_timer)
-
-        ## Create Token Layer
-        self.canvas.layers['token'] = token_layer(self.canvas)
-        #self.canvas.layers['tiles'] = tile_layer(self.canvas) #Not ready.
-
-        ### Define Grid / Background
-        self.canvas.layers['grid'].snap = False
-        self.canvas.layers['grid'].line = 0
-        #self.canvas.layers['bg'].set_texture(component.get('cherrypy')+'Textures/versa_anigre.jpg')
-        pass
-
-    def processImages(self, evt=None):
-        self.session = component.get("session")
-        if self.session.my_role() == self.session.ROLE_LURKER or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            cidx = self.canvas.parent.get_tab_index("Tiles")
-            self.canvas.parent.tabs.EnableTab(cidx, False)
-            cidx = self.canvas.parent.get_tab_index("Tokens")
-            self.canvas.parent.tabs.EnableTab(cidx, False)
-        else:
-            cidx = self.canvas.parent.get_tab_index("Tiles")
-            self.canvas.parent.tabs.EnableTab(cidx, True)
-            cidx = self.canvas.parent.get_tab_index("Tokens")
-            self.canvas.parent.tabs.EnableTab(cidx, True)
-        if not self.canvas.cacheSizeSet:
-            self.canvas.cacheSizeSet = True
-            cacheSize = component.get('settings').get_setting("ImageCacheSize")
-            if len(cacheSize): self.canvas.cacheSize = int(cacheSize)
-            else: pass
-        if not ImageHandler.Queue.empty():
-            (path, image_type, imageId) = ImageHandler.Queue.get()
-            img = wx.ImageFromMime(path[1], path[2]).ConvertToBitmap()
-            try:
-                # Now, apply the image to the proper object
-                if image_type == "miniature":
-                    min = self.canvas.layers['miniatures'].get_miniature_by_id(imageId)
-                    min.set_bmp(img)
-                elif image_type == "background" or image_type == "texture":
-                    self.canvas.layers['bg'].bg_bmp = img
-                    if image_type == "background": self.canvas.set_size([img.GetWidth(), img.GetHeight()])
-                elif image_type == "token":
-                    min = self.canvas.layers['token'].get_token_by_id(imageId)
-                    min.set_bmp(img)
-            except: pass
-
-    def on_paint(self, evt):
-        if self.canvas.layers.has_key('token') == False: self.canvas.layers['token'] = token_layer(self.canvas)
-        print 'BCG onpaint'
-        scale = self.canvas.layers['grid'].mapscale
-        scrollsize = self.canvas.GetScrollPixelsPerUnit()
-        clientsize = self.canvas.GetClientSize()
-        topleft1 = self.canvas.GetViewStart()
-        topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]]
-        if (clientsize[0] > 1) and (clientsize[1] > 1):
-            dc = wx.MemoryDC()
-            bmp = wx.EmptyBitmap(clientsize[0]+1, clientsize[1]+1)
-            dc.SelectObject(bmp)
-            dc.SetPen(wx.TRANSPARENT_PEN)
-            dc.SetBrush(wx.Brush(self.canvas.GetBackgroundColour(), wx.SOLID))
-            dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1)
-            dc.SetDeviceOrigin(-topleft[0], -topleft[1])
-            dc.SetUserScale(scale, scale)
-            self.canvas.layers['bg'].layerDraw(dc, scale, topleft, clientsize)
-            self.canvas.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
-                [clientsize[0]/scale, clientsize[1]/scale])
-
-
-            self.canvas.layers['token'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
-                [clientsize[0]/scale, clientsize[1]/scale])
-
-
-            self.canvas.layers['whiteboard'].layerDraw(dc)
-            self.canvas.layers['fog'].layerDraw(dc, topleft, clientsize)
-            dc.SetPen(wx.NullPen)
-            dc.SetBrush(wx.NullBrush)
-            dc.SelectObject(wx.NullBitmap)
-            del dc
-            wdc = self.canvas.preppaint()
-            wdc.DrawBitmap(bmp, topleft[0], topleft[1])
-            if settings.get_setting("AlwaysShowMapScale") == "1":
-                self.canvas.showmapscale(wdc)
-        try: evt.Skip()
-        except: pass
-
-    def plugin_disabled(self):
-        tabs = component.get('map_tabs')
-        map_wnd = component.get('map_wnd')
-        pages = tabs.GetPageCount()
-        while pages:
-            pages -= 1
-            if tabs.GetPageText(pages) != 'Background':
-                if tabs.GetPageText(pages) != 'Whiteboard': 
-                    tabs.RemovePage(pages)
-        layers = component.get('map_layers')
-        tabs.InsertPage(1, layers[1],"Grid")
-        tabs.InsertPage(2, layers[2],"Miniatures")
-        tabs.InsertPage(4, layers[4],"Fog")
-        tabs.InsertPage(5, layers[5],"General")
-        map_wnd.current_layer = 2
-        map_wnd.tabs.SetSelection(map_wnd.current_layer)
-    
-        ## Re Connect original MapCanvas OnPaint event.
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
-        self.canvas.Bind(wx.EVT_PAINT, self.canvas.on_paint)
-
-        ## Disconnect new proccessImages addition
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_TIMER)
-        self.canvas.Bind(wx.EVT_TIMER, self.canvas.processImages, self.canvas.image_timer)
-
-        self.canvas.layers['grid'].snap = True
-        self.canvas.layers['grid'].line = 1
-
-        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
-        #such as closing windows created by the plugin
-        #self.plugin_removecmd('/test')
-        #self.plugin_removecmd('/example')
-
-        #This is the command to delete a message handler
-        #self.plugin_delete_msg_handler('xxblank')
-
-        #This is how you should destroy a frame when the plugin is disabled
-        #This same method should be used in close_module as well
-        try:
-            self.frame.Destroy()
-        except:
-            pass
-
-    def on_test(self, cmdargs):
-        #this is just an example function for a command you create.
-        # cmdargs contains everything you typed after the command
-        # so if you typed /test this is a test, cmdargs = this is a test
-        # args are the individual arguments split. For the above example
-        # args[0] = this , args[1] = is , args[2] = a , args[3] = test
-        self.plugin_send_msg(cmdargs, '<xxblank>' + cmdargs + '</xxblank>')
-        args = cmdargs.split(None,-1)
-        msg = 'cmdargs = %s' % (cmdargs)
-        self.chat.InfoPost(msg)
-
-        if len(args) == 0:
-            self.chat.InfoPost("You have no args")
-        else:
-            i = 0
-            for n in args:
-                msg = 'args[' + str(i) + '] = ' + n
-                self.chat.InfoPost(msg)
-                i += 1
-
-    def on_xml_recive(self,id, data,xml_dom):
-        self.chat.InfoPost(self.name + ":: Message recived<br />" + data.replace("<","&lt;").replace(">","&gt;") +'<br />From id:' + str(id))
-
-    def pre_parse(self, text):
-        #This is called just before a message is parsed by openrpg
-        return text
-
-    def send_msg(self, text, send):
-        #This is called when a message is about to be sent out.
-        #It covers all messages sent by the user, before they have been formatted.
-        #If send is set to 0, the message will not be sent out to other
-        #users, but it will still be posted to the user's chat normally.
-        #Otherwise, send defaults to 1. (The message is sent as normal)
-        return text, send
-
-    def plugin_incoming_msg(self, text, type, name, player):
-        #This is called whenever a message from someone else is received, no matter
-        #what type of message it is.
-        #The text variable is the text of the message. If the type is a regular
-        #message, it is already formatted. Otherwise, it's not.
-        #The type variable is an integer which tells you the type: 1=chat, 2=whisper
-        #3=emote, 4=info, and 5=system.
-        #The name variable is the name of the player who sent you the message.
-        #The player variable contains lots of info about the player sending the
-        #message, including name, ID#, and currently-set role.
-        #Uncomment the following line to see the format for the player variable.
-        #print player
-        return text, type, name
-
-    def post_msg(self, text, myself):
-        #This is called whenever a message from anyone is about to be posted
-        #to chat; it doesn't affect the copy of the message that gets sent to others
-        #Be careful; system and info messages trigger this too.
-        return text
-
-    def refresh_counter(self):
-        #This is called once per second. That's all you need to know.
-        pass
--- a/plugins/xxblank.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxblank.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,4 +1,4 @@
-import os
+import os, wx
 import orpg.pluginhandler
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -18,6 +18,16 @@
         #to set their proper values.
         self.sample_variable = {}
 
+    def plugin_menu(self):
+        ## This is a standardized Menu item.  It connects to plugin_toggle where you can set events.
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
+
 
     def plugin_enabled(self):
         #You can add new /commands like
--- a/plugins/xxchatnotify.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxchatnotify.py	Sat Jun 12 03:50:37 2010 -0500
@@ -126,14 +126,15 @@
 
 
     def plugin_incoming_msg(self, text, type, name, player):
-        if (self.notify == 'beep' or self.notify == 'both') and (self.type == 'all' or type == 2):
-            if self.soundfile == 'None':
-                wx.CallAfter(wx.Bell)
-                wx.CallAfter(wx.Bell)
-            else:
-                wx.CallAfter(self.sound_player.play, self.soundfile, self.soundloc)
-        if (self.notify == 'flash' or self.notify == 'both') and (self.type == 'all' or type == 2):
-            wx.CallAfter(self.mainframe.RequestUserAttention)
+        if not self.topframe.IsActive():
+            if (self.notify == 'beep' or self.notify == 'both') and (self.type == 'all' or type == 2):
+                if self.soundfile == 'None':
+                    wx.CallAfter(wx.Bell)
+                    wx.CallAfter(wx.Bell)
+                else:
+                    wx.CallAfter(self.sound_player.play, self.soundfile, self.soundloc)
+            if (self.notify == 'flash' or self.notify == 'both') and (self.type == 'all' or type == 2):
+                wx.CallAfter(self.mainframe.RequestUserAttention)
         return text, type, name
 
 
--- a/plugins/xxgsc.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxgsc.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,9 +1,7 @@
-import os
-from orpg.orpg_wx import *
+import os, wx
 import random
 import orpg.pluginhandler
 
-
 ID_ROLL = wx.NewId()
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -15,7 +13,7 @@
         orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
 
         self.name = 'Game Status Controller'
-        self.author = 'Woody, updated by mDuo13'
+        self.author = 'Woody, updated by mDuo13 and Calchexas'
         self.help = 'This plugin lets you quickly and easily manage a status that includes \n'
         self.help += 'your HP and AC for AD&D 2nd Edition. Type /gsc to open up the manager\n'
         self.help += 'window, and from there just change the values as necessary and the changes\n'
@@ -26,12 +24,14 @@
 
     def plugin_enabled(self):
         self.plugin_addcommand('/gsc', self.on_gsc, '- The GSC command')
-        self.frame = RollerFrame(None, -1, "Game Status Ctrl (GSC)", self)
+        self.frame = RollerFrame(None, -1, "Game Status Controller (GSC)", self)
         self.frame.Hide()
 
-        item = wx.MenuItem(self.menu, wx.ID_ANY, "GSC Window", "GSC Window", wx.ITEM_CHECK)
-        self.topframe.Bind(wx.EVT_MENU, self._toggleWindow, item)
-        self.menu.AppendItem(item)
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'GSC Window')
+        self.topframe.Bind(wx.EVT_MENU, self._toggleWindow, self.toggle)
+        self.toggle.Check(False)
 
     def plugin_disabled(self):
         self.plugin_removecmd('/gsc')
@@ -48,26 +48,26 @@
 
     #Events
     def _toggleWindow(self, evt):
-        id = evt.GetId()
-        item = self.menu.FindItemById(id)
         if self.frame.IsShown():
             self.frame.Hide()
-            item.Check(False)
+            self.toggle.Check(False)
         else:
             self.frame.Show()
-            item.Check(True)
+            self.toggle.Check(True)
 
 
 class RollerFrame(wx.Frame):
     def __init__(self, parent, ID, title, plugin):
         wx.Frame.__init__(self, parent, ID, title,
-                         wx.DefaultPosition, wx.Size(200, 70))
+                         wx.DefaultPosition, wx.Size(250, 110))
 
         self.settings = plugin.settings
         self.session = plugin.session
         self.plugin = plugin
 
         self.panel = wx.Panel(self,-1)
+        sizer = wx.GridBagSizer(1, 2)
+        self.panel.SetSizer(sizer)
         menu = wx.Menu()
         menu.AppendSeparator()
         menu.Append(wx.ID_EXIT, "&Close", "Close this window")
@@ -77,18 +77,42 @@
 
         self.old_idle = self.settings.get_setting('IdleStatusAlias')
 
-        wx.StaticText(self.panel, -1, "AC:", wx.Point(0, 5))
-        self.ac = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(18, 0), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        ac_text = wx.StaticText(self.panel, -1, "AC:", wx.Point(0, 5))
+        self.ac = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(18, 0), wx.Size(45, -1), min = -100, max = 100, initial = 10)
         self.ac.SetValue(10)
 
-        wx.StaticText(self.panel, -1, "/", wx.Point(136, 5))
-        self.max_hp = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(144, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
+        touch_text = wx.StaticText(self.panel, -1, "Touch:", wx.Point(0, 25))
+        self.touch = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(60, 25), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        self.touch.SetValue(10)
+
+        ff_text = wx.StaticText(self.panel, -1, "FF:", wx.Point(115, 25))
+        self.ff = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(165, 25), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        self.ff.SetValue(10)
+        
+        max_hp_text = wx.StaticText(self.panel, -1, "/", wx.Point(150, 5))
+        self.max_hp = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(158, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
         self.max_hp.SetValue(10)
 
-        wx.StaticText(self.panel, -1, "HP:", wx.Point(65, 5))
-        self.hp = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(83, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
+        hp_text = wx.StaticText(self.panel, -1, "HP:", wx.Point(80, 5))
+        self.hp = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(98, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
         self.hp.SetValue(10)
 
+        sizer.Add(ac_text, (1,0), span=(1,1))
+        sizer.Add(self.ac, (1,1), span=(1,1))
+        sizer.Add(touch_text, (1,2), span=(1,1))
+        sizer.Add(self.touch, (1,3), span=(1,1))
+        sizer.Add(ff_text, (1,4), span=(1,1))
+        sizer.Add(self.ff, (1,5), span=(1,1))
+        sizer.Add(hp_text, (0,0), span=(1,1))
+        sizer.Add(self.hp, (0,1), span=(1,1))
+        sizer.Add(max_hp_text, (0,2), span=(1,1))
+        sizer.Add(self.max_hp, (0,3), span=(1,1))
+        self.SetMinSize((350,100))
         self.Bind(wx.EVT_SPINCTRL, self.SetStatus, id=ID_ROLL)
         self.Bind(wx.EVT_TEXT, self.SetStatus, id=ID_ROLL)
         self.Bind(wx.EVT_MENU, self.TimeToQuit, id=wx.ID_EXIT)
@@ -96,7 +120,7 @@
         self.SetStatus(None)
 
     def SetStatus(self, evt):
-        new_status = "AC: " + str(self.ac.GetValue()) + "   HP: " + str(self.hp.GetValue()) + "/" + str(self.max_hp.GetValue())
+        new_status = "AC: " + str(self.ac.GetValue()) + " (Touch: " + str(self.touch.GetValue()) + " FF: " + str(self.ff.GetValue()) + ")" + " HP: " + str(self.hp.GetValue()) + "/" + str(self.max_hp.GetValue())
         self.settings.set_setting('IdleStatusAlias',new_status)
         self.session.set_text_status(new_status)
 
--- a/plugins/xxhiddendice.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxhiddendice.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,6 +1,6 @@
-import os
-import re
+import os, re, wx
 import orpg.pluginhandler
+from orpg.tools.InterParse import Parse
 
 class Plugin(orpg.pluginhandler.PluginHandler):
     # Initialization subroutine.
@@ -23,32 +23,39 @@
         self.hiddenrolls = []
         self.dicere = "\{([0-9]*d[0-9]*.+)\}"
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
 
     def plugin_enabled(self):
         pass
 
-
     def plugin_disabled(self):
         pass
 
-
     def pre_parse(self, text):
-        m = re.search(self.dicere, text)
-        while m:
-            roll = "[" + m.group(1) + "]"
-            self.hiddenrolls += [self.chat.ParseDice(roll)]
-            text = text[:m.start()] + "(hidden roll)" + text[m.end():]
+        if self.toggle.IsChecked() == True:
             m = re.search(self.dicere, text)
+            while m:
+                roll = "[" + m.group(1) + "]"
+                self.hiddenrolls += [Parse.Dice(roll)]
+                text = text[:m.start()] + "(hidden roll)" + text[m.end():]
+                m = re.search(self.dicere, text)
         return text
 
     def post_msg(self, text, myself):
-        c = 0
-        a = text.find("(hidden roll)")
-
-        while len(self.hiddenrolls) > c and a > -1:
-            text = text[:a+14].replace("(hidden roll)", self.hiddenrolls[c]) + text[a+14:]
+        if self.toggle.IsChecked() == True:
+            c = 0
             a = text.find("(hidden roll)")
-            c += 1
-        if c > 0:
-            self.hiddenrolls = []
+            while len(self.hiddenrolls) > c and a > -1:
+                text = text[:a+14].replace("(hidden roll)", self.hiddenrolls[c]) + text[a+14:]
+                a = text.find("(hidden roll)")
+                c += 1
+            if c > 0:
+                self.hiddenrolls = []
         return text
--- a/plugins/xxmouse-zoom.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxmouse-zoom.py	Sat Jun 12 03:50:37 2010 -0500
@@ -19,6 +19,17 @@
         self.help += 'wheel and the map will zoom in or out.  And FAST too! \n'
         self.help += 'This plugin is designed for Grumpy Goblin and Ornery Orc.'
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        if self.toggle.IsChecked() == False: self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        if self.toggle.IsChecked() == True:
+            self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.MouseWheel)
+
     def plugin_enabled(self):
         try: self.canvas = component.get('map').canvas
         except: self.canvas = open_rpg.get_component('map').canvas
@@ -26,12 +37,12 @@
 
     def MouseWheel(self, evt):
         if evt.CmdDown():
-            print evt.GetWheelRotation()
             if evt.GetWheelRotation() > 0: self.canvas.on_zoom_in(None)
             elif evt.GetWheelRotation() < 0: self.canvas.on_zoom_out(None)
             else: pass
         else: self.canvas.on_scroll(evt)
 
     def plugin_disabled(self):
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        try: self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        except: pass
 
--- a/plugins/xxsimpleinit.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxsimpleinit.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,7 +1,7 @@
-import os
+import os, wx
 import orpg.pluginhandler
 from orpg.orpgCore import *
-import wx
+from orpg.tools.InterParse import Parse
 
 class Plugin(orpg.pluginhandler.PluginHandler):
     # Initialization subroutine.
@@ -215,7 +215,7 @@
         for i in xrange(0, self.frame.initList.GetItemCount()):
             self.frame.currentInit = i
             if self.frame.currentInit.manual == 'No':
-                initRoll = self.chat.ParseDice('[1d20' + self.frame.currentInit.initMod + ']')
+                initRoll = Parse.Dice('[1d20' + self.frame.currentInit.initMod + ']')
 
                 initRoll = initRoll.split('(')
                 initRoll = initRoll[1].replace(')','')
--- a/plugins/xxspell.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxspell.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,4 +1,4 @@
-import os
+import os, wx
 import orpg.pluginhandler
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -17,6 +17,15 @@
         self.help += "even corrects other people's spelling."
         self.checklist = {}
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
+
     def plugin_enabled(self):
         #This is where you set any variables that need to be initalized when your plugin starts
         #You can add new /commands like
@@ -34,11 +43,13 @@
         return text
 
     def plugin_incoming_msg(self, text, type, name, player):
-        text = self.replace(text)
+        if self.toggle.IsChecked() == True:
+            text = self.replace(text)
         return text, type, name
 
     def pre_parse(self, text):
-        text = self.replace(text)
+        if self.toggle.IsChecked() == True:
+            text = self.replace(text)
         return text
 
     def on_spell(self, cmdargs):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/xxstdnamespace.py	Sat Jun 12 03:50:37 2010 -0500
@@ -0,0 +1,105 @@
+import os, wx, re
+import orpg.pluginhandler
+from orpg.tools.InterParse import Parse
+from orpg.orpgCore import component
+from xml.etree.ElementTree import iselement
+
+class Plugin(orpg.pluginhandler.PluginHandler):
+    # Initialization subroutine.
+    #
+    # !self : instance of self
+    # !openrpg : instance of the the base openrpg control
+    def __init__(self, plugindb, parent):
+        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
+
+        # The Following code should be edited to contain the proper information
+        self.name = 'Standard Namespace'
+        self.author = 'Prof. Ebral'
+        self.help = 'The Standard Namespace plugin allows for users of Traipse to use '
+        self.help += 'the Standard Namespace syntax of !@ :: @!\n\n'
+        self.help += 'This plugin modifies the External method, so context sensivity\n'
+        self.help += 'is not calculated when using the Standard syntax. References must '
+        self.help += 'have a unique name.'
+
+        self.NameSpaceE = Parse.NameSpaceE
+        self.parseMethods = {'Traipse': self.NameSpaceE, 'Standard': self.NameSpaceS}
+
+    def NameSpaceS(self, s): ## Re define NameSpace External
+        reg1 = re.compile("(!@(.*?)@!)") ## Include 'Standard' method
+        reg2 = re.compile("(!&(.*?)&!)")
+        ## Before anyone rags on me about how this is a useless plugin, or that two methods are confusing,
+        ## consider that this will be fully integrated later. Then consider that you can now create a reference
+        ## with a reference. !@ :: !& :: &! :: @!
+        matches = reg1.findall(s) + reg2.findall(s)
+        newstr = False
+        nodeable = ['rpg_grid_handler', 'container_handler', 
+                    'group_handler', 'tabber_handler', 
+                    'splitter_handler', 'form_handler', 'textctrl_handler']
+        for i in xrange(0,len(matches)):
+            find = matches[i][1].split('::')
+            node = component.get('tree').xml_root
+            if not iselement(node): 
+                s = s.replace(matches[i][0], 'Invalid Reference!', 1); 
+                s = self.NameSpaceS(s)
+                return s
+            for x in xrange(0, len(find)):
+                namespace = node.getiterator('nodehandler')
+                for node in namespace:
+                    if find[x] == node.get('name'):
+                        if node.get('class') not in nodeable: continue
+                        if node.get('class') == 'rpg_grid_handler':
+                            try: newstr = Parse.NameSpaceGrid(find[x+1], node); break
+                            except: newstr = 'Invalid Grid Reference!'
+                        try:
+                            if Parse.FutureCheck(node, find[x+1]): break
+                            else: continue
+                        except:
+                            if x == len(find)-1:
+                                if node.find('text') != None: newstr = str(node.find('text').text) 
+                                else: newstr = 'Invalid Reference!'
+                                break
+                            else: break
+            if not newstr: newstr = 'Invalid Reference!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = Parse.ParseLogic(s, node)
+        return s
+
+    def plugin_menu(self):
+        ## This is a standardized Menu item.  It connects to plugin_toggle where you can set events.
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        if self.toggle.IsChecked() == True: 
+            Parse.NameSpaceE = self.parseMethods['Standard']
+            self.plugindb.SetString('xxstdnamespace', 'Standard', 'True')
+        if self.toggle.IsChecked() == False: 
+            Parse.NameSpaceE = self.parseMethods['Traipse']
+            self.plugindb.SetString('xxstdnamespace', 'Standard', 'False')
+        pass
+
+    def plugin_enabled(self):
+        self.onoroff = self.plugindb.GetString('xxstdnamespace', 'Standard', '') or 'False'
+        self.toggle.Check(True) if self.onoroff == 'True' else self.toggle.Check(False)
+        Parse.NameSpaceE = self.parseMethods['Standard'] if self.onoroff == 'True' else self.parseMethods['Traipse']
+        pass
+
+    def plugin_disabled(self):
+        Parse.NameSpaceE = self.parseMethods['Traipse']
+
+    def pre_parse(self, text):
+        return text
+
+    def send_msg(self, text, send):
+        return text, send
+
+    def plugin_incoming_msg(self, text, type, name, player):
+        return text, type, name
+
+    def post_msg(self, text, myself):
+        return text
+
+    def refresh_counter(self):
+        pass
--- a/plugins/xxurl2link.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxurl2link.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,6 +1,5 @@
-import os
+import os, re, wx
 import orpg.pluginhandler
-import re
 
 class Plugin(orpg.pluginhandler.PluginHandler):
     # Initialization subroutine.
@@ -10,34 +9,45 @@
     def __init__(self, plugindb, parent):
         orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
 
-        # The Following code should be edited to contain the proper information
         self.name = 'URL to link conversion'
         self.author = 'tdb30 tbaleno@wrathof.com'
         self.help = "This plugin automaticaly wraps urls in link tags\n"
         self.help += "making them clickable."
 
-        self.url_regex = None
-        self.mailto_regex = None
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+
+    def plugin_toggle(self, evt):
+        if self.toggle.IsChecked() == True: self.plugindb.SetString('xxurl2link', 'url2link', 'True')
+        if self.toggle.IsChecked() == False: self.plugindb.SetString('xxurl2link', 'url2link', 'False')
+        pass
 
     def plugin_enabled(self):
-        #This is where you set any variables that need to be initalized when your plugin starts
-        self.url_regex = re.compile("(?<![\[=\"a-z0-9:/.])((?:http|ftp|gopher)://)?(?<![@a-z])((?:[a-z0-9\-]+[-.]?[a-z0-9]+)*\.(?:[a-z]{2,4})(?:[a-z0-9_=\?\#\&~\%\.\-/\:\+;]*))", re.I)
-
-        self.mailto_regex = re.compile("(?<![=\"a-z0-9:/.])((?:[a-z0-9]+[_]?[a-z0-9]*)+@{1}(?:[a-z0-9]+[-.]?[a-z0-9]+)*\.(?:[a-z]{2,4}))", re.I)
+        self.url_regex = re.compile( #from Paul Hayman of geekzilla
+                    "((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.I)
+        self.mailto_regex = re.compile( #Taken from Django
+                    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
+                    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
+                    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)
+        self.link = self.plugindb.GetString('xxurl2link', 'url2link', '') or 'False'
+        self.toggle.Check(True) if self.link == 'True' else self.toggle.Check(False)
 
     def plugin_disabled(self):
-        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
-        #such as closing windows created by the plugin
         pass
 
     def pre_parse(self, text):
-        text = self.mailto_regex.sub(self.regmailsub, text)
-        text = self.url_regex.sub(self.regurlsub, text)
+        text2 = text
+        if self.toggle.IsChecked() == True:
+            text = self.mailto_regex.sub(self.regmailsub, text)
+            text = self.url_regex.sub(self.regurlsub, text)
         return text
 
     def plugin_incoming_msg(self, text, type, name, player):
-        text = self.mailto_regex.sub(self.regmailsub, text)
-        text = self.url_regex.sub(self.regurlsub, text)
+        if self.toggle.IsChecked() == True:
+            text = self.mailto_regex.sub(self.regmailsub, text)
+            text = self.url_regex.sub(self.regurlsub, text)
         return text, type, name
 
     def regmailsub(self, m):
@@ -46,7 +56,5 @@
 
     def regurlsub(self, m):
         link = m.group(2)
-        if m.group(1) != None:
-            return '<a href="' + m.group(1).lower() + link + '">' + m.group(0) + '</a>'
-        else:
-            return '<a href="http://' + link + '">' + link + '</a>'
+        if m.group(1) != None: return '<a href="' + m.group(1).lower() + '">' + m.group(0) + '</a>'
+        else: return '<a href="http://' + link + '">' + link + '</a>'
--- a/readme.txt	Fri Jan 15 22:45:51 2010 -0600
+++ b/readme.txt	Sat Jun 12 03:50:37 2010 -0500
@@ -1,9 +1,18 @@
-How to use OpenRPG version 1.7.x
-Make sure you have installed python 2.5+ and wxPython 2.8+!
+Welcome to Traipse 'OpenRPG' Ornery Orc
+Traipse is a fork of the original OpenRPG software. Traipse 
+provides the best stability of any OpenRPG fork, and the best
+features of any OpenRPG version
+
+How to use Traipse 'OpenRPG':
 
-Launching OpenRPG:
-OpenRPG can be launch by executing the OpenRPG.pyw script
-located in the openrpg folder.  On windows, Macs, and
+Minimum software requirements
+* Python 2.5.2
+* wx.Python 2.8.1.9
+
+Launching Traipse 'OpenRPG':
+
+OpenRPG can be launch by executing the Traipse.pyw script
+located in the folder you ran setup.py.  On windows, Macs, and
 Unix with a GUI, this can be accomplished by double
 clicking OpenRPG.pyw. From a shell, type: python OpenRPG.pyw
 
@@ -11,8 +20,8 @@
 You want to launch your own server execute the
 Server.py.
 
-For more info on how to use OpenRPG,
-visit http://www.openrpg.com
+For more info on how to use Traipse 'OpenRPG',
+visit http://www.knowledgearcana.com/traipse-openrpg
 
 
 -OpenRPG Team
--- a/start_noupdate.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-
-import pyver
-pyver.checkPyVersion()
-
-#Update Manager
-from orpg.orpg_wx import *
-import upmana.updatemana
-app = upmana.updatemana.updateApp(0)
-app.MainLoop()
-
-#Main Program
-from orpg.orpg_wx import *
-import orpg.main
-
-if WXLOADED:
-    mainapp = orpg.main.orpgApp(0)
-    mainapp.MainLoop()
-else:
-    print "You really really need wx!"
--- a/upmana/updatemana.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/upmana/updatemana.py	Sat Jun 12 03:50:37 2010 -0500
@@ -12,8 +12,9 @@
 class Term2Win(object):
     # A stdout redirector.  Allows the messages from Mercurial to be seen in the Install Window
     def write(self, text):
-        statbar.SetStatusText(text)
-        wx.Yield()
+        self.closed = sys.__stdout__.closed
+        self.flush = sys.__stdout__.flush
+        statbar.SetStatusText(text.replace('\n', ''))
         sys.__stdout__.write(text)
 
 class Updater(wx.Panel):
@@ -21,7 +22,10 @@
         wx.Panel.__init__(self, parent)
         ### Status Bar ###
         #statbar.SetStatusText('Select a Package and Update')
-        statbar.SetStatusText('New Status Bar')
+        #statbar.SetStatusText('New Status Bar')
+
+        self.timer = wx.Timer(self, 1)
+        self.count = 0
 
         ### Update Manager
         self.ui = ui.ui()
@@ -44,7 +48,7 @@
         self.buttons['update'] = wx.Button(self, wx.ID_ANY, "Update Now")
         self.buttons['finish'] = wx.Button(self, wx.ID_ANY, "Finish")
 
-        self.sizer.Add(self.changelog, (0,0), span=(4,1), flag=wx.EXPAND)
+        self.sizer.Add(self.changelog, (0,0), span=(5,1), flag=wx.EXPAND)
         self.sizer.Add(self.filelist, (0,1), span=(1,3), flag=wx.EXPAND)
 
         self.sizer.Add(self.buttons['progress_bar'], (1,1), span=(1,3), flag=wx.EXPAND)
@@ -55,7 +59,7 @@
         self.sizer.Add(self.buttons['advanced'], (2,3), flag=wx.EXPAND)
         self.sizer.Add(self.buttons['update'], (3,3), flag=wx.EXPAND)
         self.sizer.Add(self.buttons['finish'], (4,3), flag=wx.EXPAND)
-        #self.buttons['finish'].Disable()
+        self.buttons['progress_bar'].SetValue(100)
         self.sizer.AddGrowableCol(0)
         self.sizer.AddGrowableRow(0)
         self.SetSizer(self.sizer)
@@ -76,6 +80,37 @@
         self.Bind(wx.EVT_BUTTON, self.ChooseBranch, self.buttons['advanced'])
         self.Bind(wx.EVT_CHECKBOX, self.ToggleAutoUpdate, self.buttons['auto_check'])
         self.Bind(wx.EVT_CHECKBOX, self.ToggleNoUpdate, self.buttons['no_check'])
+        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
+
+    def OnTimer(self, event):
+        statbar.SetStatusText('Checking For Updates')
+        self.count = self.count + 1
+        self.buttons['progress_bar'].SetValue(self.count)
+        if self.count == 100:
+            self.timer.Stop()
+            statbar.SetStatusText('No Updates Available')
+
+    def UpdateCheck(self):
+        self.timer.Start(100)
+        self.count = 3
+        self.buttons['progress_bar'].SetValue(3)
+        try:
+            doUpdate = commands.incoming(self.ui, self.repo, 
+                        manifest.GetString('default', 'repo', ''), 
+                        force=True, bundle=False)
+            if doUpdate:
+                statbar.SetStatusText('No Updates Available')
+                self.buttons['progress_bar'].SetValue(100)
+                self.timer.Stop()
+            else:
+                statbar.SetStatusText('Refresh Repo For Updated Source')
+                self.buttons['progress_bar'].SetValue(100)
+                self.timer.Stop()
+        except:
+            statbar.SetStatusText('No Connection Found')
+            self.buttons['progress_bar'].SetValue(100)
+            self.timer.Stop()
+
 
     def ToggleAutoUpdate(self, event):
         if self.buttons['auto_check'].GetValue() == True:
@@ -122,16 +157,14 @@
                 os.removedirs(temp+dir1)
 
     def LoadDoc(self):
-        ignore = open(self.filename)
+        manifest = open(self.filename)
         self.ignorelist = []
-        for i in ignore: self.ignorelist.append(str(i [:len(i)-1]))
-        manifest = ignore.readlines()
-        ignore.close()
+        ignore = manifest.readlines()
+        for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1]))
+        manifest.close()
 
     def Finish(self, evt=None):
-        try: component.get('upmana-win').OnClose(None)
-        except Exception, e:
-            print 'Fail', e; exit()
+        component.get('upmana-win').OnClose(None)
 
     def ChooseBranch(self, evt=None):
         dlg = wx.Dialog(self, wx.ID_ANY, "Package Selector", style=wx.DEFAULT_DIALOG_STYLE)
@@ -586,14 +619,14 @@
             dlg.Destroy(); pass
 
     def LoadDoc(self):
-        ignore = open(self.filename)
+        manifest = open(self.filename)
         self.ignorelist = []
-        for i in ignore: self.ignorelist.append(str(i [:len(i)-1]))
-        manifest = ignore.readlines()
-        ignore.close()
+        ignore = manifest.readlines()
+        for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1]))
+        manifest.close()
 
     def get_packages(self, type=None):
-        #Fixed and ready for Test. Can be cleaner
+        #Can be cleaner
         self.package_list = []
         b = self.repo.branchtags()
         heads = dict.fromkeys(self.repo.heads(), 1) #The code below looks superfluous but there is good info inside
@@ -689,17 +722,18 @@
 
         global statbar
         statbar = self.CreateStatusBar()
+        sys.stdout = Term2Win()
         self.Centre()
 
         # create the page windows as children of the notebook
-        page1 = Updater(nb, openrpg)
+        self.page1 = Updater(nb, openrpg)
         page2 = Repos(nb, openrpg)
         page3 = Manifest(nb)
         page4 = Control(nb)
         page5 = Help(nb)
 
         # add the pages to the notebook with the label to show on the tab
-        nb.AddPage(page1, "Updater")
+        nb.AddPage(self.page1, "Updater")
         nb.AddPage(page2, "Repos")
         nb.AddPage(page3, "Manifest")
         nb.AddPage(page4, "Control")
@@ -721,23 +755,24 @@
 
 class updateApp(wx.App):
     def OnInit(self):
-        self.main = False
-        sys.stdout = Term2Win()
+        self.main = False; self.autoUpdate = False; self.noUpdate = False
         logger._set_log_to_console(False)
         logger.note("Updater Start")
         component.add('validate', validate)
-        self.updater = updaterFrame(self, "OpenRPG Update Manager 1.0", 
+        self.updater = updaterFrame(self, "OpenRPG Update Manager 1.2", 
                                 component, manifest, self.main)
         if manifest.GetString("updatemana", "auto_update", "") == 'on' and self.main == False:
-            self.AutoUpdate(); self.OnExit()
+            self.AutoUpdate(); self.OnExit(); self.autoUpdate = True
         else: pass
         if manifest.GetString('updatemana', 'no_update', '') == 'on' and self.main == False: 
-            self.OnExit()
+            self.OnExit(); self.noUpdate = True
         else: pass
-        try:
-            self.updater.Show()
-            self.updater.Fit()
-        except: pass
+        if not (self.autoUpdate or self.noUpdate):
+            try:
+                self.updater.Show()
+                self.updater.Fit()
+                if not self.main: self.updater.page1.UpdateCheck()
+            except: pass
         return True
 
     def AutoUpdate(self):
@@ -746,13 +781,16 @@
         self.c = self.repo.changectx('tip')
         self.current = self.repo.dirstate.branch()
 
-        capture = manifest.GetString('updaterepo', 'default', '')
+        capture = manifest.GetString('default', 'repo', '')
         if capture != '':
-            commands.pull(self.ui, self.repo, capture, rev='', update=False, force=True)
+            try: commands.pull(self.ui, self.repo, capture, rev='', update=False, force=True)
+            except:
+                wx.MessageBox('No Connection Found.  Skipping Auto Update!', 'Info')
+                return
             filename = 'ignorelist.txt'
             self.filename = dir_struct["home"] + 'upmana' + os.sep + filename
             component.get('validate').config_file(filename, "default_ignorelist.txt")
-            self.mana = self.LoadDoc()
+            self.mana = self.LoadDoc(); ignored = []
             temp = dir_struct["home"] + 'upmana' + os.sep + 'tmp' + os.sep
             for ignore in self.ignorelist:
                 if len(ignore.split('/')) > 1:
@@ -761,25 +799,27 @@
                         dir1 += ignore.split('/')[gets] + os.sep
                         gets += 1
                     os.makedirs(temp+dir1)
-                shutil.copy(ignore, temp + dir1 + ignore.split('/')[len(ignore.split('/')) - 1])
+                ignoredfile = temp + dir1 + ignore.split('/')[len(ignore.split('/')) - 1]
+                ignored.append(ignoredfile)
+                shutil.copy(ignore, ignoredfile)
             hg.clean(self.repo, self.current)
             for ignore in self.ignorelist:
-                shutil.copyfile(temp + ignore.split('/')[len(ignore.split('/')) - 1], ignore)
-                os.remove(temp + ignore.split('/')[len(ignore.split('/')) - 1])
+                shutil.copyfile(ignored.index(ignore), ignore)
+                os.remove(ignored.index(ignore))
                 if len(ignore.split('/')) > 1:
                     gets = 0; dir1 = ''
                     while gets != len(ignore.split('/'))-1:
                         dir1 += ignore.split('/')[gets] + os.sep
                         gets += 1
                     os.removedirs(temp+dir1)
-        else: wx.MessageBox('No default Rpository set.  Skipping Auto Update!', 'Info')
+        else: wx.MessageBox('Default Repo Not Found.  Skipping Auto Update!', 'Info')
 
     def LoadDoc(self):
-        ignore = open(self.filename)
+        manifest = open(self.filename)
         self.ignorelist = []
-        for i in ignore: self.ignorelist.append(str(i [:len(i)-1]))
-        manifest = ignore.readlines()
-        ignore.close()
+        ignore = manifest.readlines()
+        for i in ignore: print i; self.ignorelist.append(str(i[:len(i)-1]))
+        manifest.close()
 
     def OnExit(self):
         imported = ['manifest', 'orpg.dirpath', 'orpg.orpgCore', 'orpg.orpg_version', 
--- a/upmana/validate.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/upmana/validate.py	Sat Jun 12 03:50:37 2010 -0500
@@ -1,11 +1,3 @@
-# file: config_files.py
-#
-# Author: Todd Faris (Snowdog)
-# Date:   5/10/2005
-#
-# Misc. config file service methods
-#
-
 from orpg.dirpath import dir_struct
 import os