changeset 140:e842a5f1b775 beta

Traipse Beta 'OpenRPG' {091123-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 (Beta) Added Bookmarks Fix to Remote Admin Commands Minor fix to text based Server Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Added 'boot' command to remote admin Added confirmation window for sent nodes Minor changes to allow for portability to an OpenSUSE linux OS Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Zoom Mouse plugin added Images added to Plugin UI Switching to Element Tree Map efficiency, from FlexiRPG Added Status Bar to Update Manager default_manifest.xml renamed to default_upmana.xml Cleaner clode for saved repositories New TrueDebug Class in orpg_log (See documentation for usage) Mercurial's hgweb folder is ported to upmana Pretty important update that can help remove thousands of dead children from your gametree. Children, <forms />, <group_atts />, <horizontal />, <cols />, <rows />, <height />, etc... are all tags now. Check your gametree and look for dead children!! New Gametree Recursion method, mapping, and context sensitivity. !Infinite Loops return error instead of freezing the software! New Syntax added for custom PC sheets Tip of the Day added, from Core and community Fixed Whiteboard ID to prevent random line or text deleting. Modified ID's to prevent non updated clients from ruining the fix.
author sirebral
date Mon, 23 Nov 2009 03:36:26 -0600
parents dcf4fbe09b70
children 2345c12d93a7
files data/tips.txt images/8ball.gif images/WAmisc7.ico images/WAmisc9.ico images/add_filter.gif images/apoc.gif images/arc.png images/b_d10.gif images/b_d100.gif images/b_d12.gif images/b_d20.gif images/b_d4.gif images/b_d6.gif images/b_d8.gif images/bold.gif images/book.gif images/bricktile.gif images/browser.gif images/bullet.gif images/car.gif images/ccmap.gif images/chess.gif images/circle.png images/clear.gif images/close_wnd.bmp images/compass.gif images/compass.ico images/connect.gif images/crosshair.gif images/cyborg.gif images/d10.gif images/d20.gif images/d20.ico images/d20.xpm images/d20_logo.gif images/d4.gif images/d8.gif images/dash.png images/defaultmap.png images/delete_filter.gif images/dice.bmp images/die.gif images/divider.png images/draw.gif images/drugs.gif images/earth.gif images/edit_filter.gif images/fetching.png images/flask.gif images/flask.ico images/fogoff.png images/fogon.png images/folder.gif images/form.png images/frame.bmp images/gear.gif images/goblin.gif images/goblin.ico images/grenade.gif images/grid.gif images/grid.ico images/gun1.gif images/gun2.gif images/help.gif images/hidefog.png images/html.gif images/html.ico images/icons.xml images/img.gif images/install.gif images/italic.gif images/knight.gif images/labtop.gif images/money.gif images/mouse.gif images/move.gif images/ninja.gif images/noplayer.gif images/note.gif images/note.ico images/open.bmp images/orc.gif images/oriental.gif images/pin.gif images/planet.gif images/player-whisper.gif images/player.gif images/python55.gif images/questionhead.gif images/r2d2.gif images/rectangle.png images/rome.gif images/save.bmp images/sflogo.png images/shades.gif images/showfog.png images/skull.gif images/skull_16.gif images/smsword2.gif images/spears.gif images/splash.gif images/splash.jpg images/splash1.jpg images/splash13.jpg images/splitwin.bmp images/spotlight.png images/startrek.gif images/sword.gif images/tab.bmp images/tab_close.png images/tab_on.png images/tabber.png images/tank1.gif images/tank2.gif images/tape.gif images/text.png images/thief.gif images/tiefighter.gif images/underlined.gif images/wizard1.gif images/wxPyButton.png images/wxWinButton.png images/zoom_in.gif images/zoom_out.gif myfiles/webfiles/Textures/Copyright Notice.txt myfiles/webfiles/Textures/grass-natural.jpg myfiles/webfiles/Textures/grass11.jpg myfiles/webfiles/Textures/sandwave.jpg myfiles/webfiles/Textures/steelpops11.jpg myfiles/webfiles/Textures/versa_anigre.jpg myfiles/webfiles/Textures/water06.jpg myfiles/webfiles/Textures/water20.jpg orpg/chat/chat_util.py orpg/chat/chatwnd.py orpg/gametree/gametree.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/rpg_grid.py orpg/main.py orpg/mapper/background.py orpg/mapper/background_msg.py orpg/mapper/base_msg.py orpg/mapper/fog.py orpg/mapper/fog_msg.py orpg/mapper/grid_msg.py orpg/mapper/images.py orpg/mapper/map.py orpg/mapper/map_msg.py orpg/mapper/miniatures.py orpg/mapper/miniatures_handler.py orpg/mapper/miniatures_msg.py orpg/mapper/whiteboard.py orpg/mapper/whiteboard_msg.py orpg/networking/gsclient.py orpg/networking/mplay_client.py orpg/networking/mplay_server.py orpg/networking/mplay_server_gui.py orpg/orpg_version.py orpg/plugindb.py orpg/templates/feature.xml plugins/xxmouse-zoom.py upmana/manifest.py
diffstat 29 files changed, 698 insertions(+), 627 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/tips.txt	Mon Nov 23 03:36:26 2009 -0600
@@ -0,0 +1,43 @@
+Traipse OpenRPG is a fork of the original OpenRPG software. Traipse has been designed to be easy to use while offering superb functionality and strong stability.
+
+You can find other OpenRPG users by clicking "Game Server/Browse Servers" and then double clicking on one of the servers. Try the top one: it has the most active users.
+
+For a technical question about OpenRPG try the RPGObjects OpenRPG forum here: http://www.rpgobjects.com/forum/index.php?action=vtopic&forum=1
+
+Many of the OpenRPG servers have associated web sites that help players find campaigns, find OpenRPG resources such as miniatures and charachter sheets, and can answer other questions.
+
+The Traipes Suite has a debug console that allows you to see what would appear in a regular console. The debug console allows you to copy and paste any errors that occur, and the Bug Report button allows you to submit your bug while still playing.
+
+You may observe an OpenRPG session in progress by entering a room that someone else has created. Be careful not to annoy people. If you have questions use "Whisper". Red rooms are private.
+
+The Traipse Update Manager allows you to download source code from any OpenRPG fork in the Repos tab. Just give the repository a name, then add the url and press refresh. Here are two to try it with: Traipse-Dev: http://hg.assembla.com/traipse_dev and OpenRPG-Core: http://hg.assembla.com/openrpg
+
+Room Moderation helps prevent annyoing lurkers from disrupting your game. Turn on Room Moderation by right clicking on your name in the player list and find the Moderation sub menu.
+
+OpenRPG servers are maintained by private individuals. When you connect to a new server please take a moment to read any rules they might have, such as not posting images while in the lobby.
+
+OpenRPG images are hosted in one of three ways: by a URL to any image hosting site such as Photobucket or Imageshack, by a URL to an image served by your own client program (CherryPy) or by a file uploaded to OpenRPG's dedicated image server from your local file system.
+
+You can drag an image file straight from your file system to OpenRPG's map using the Remote Image Server. In Pious Paladin this feature will be added to CherryPy so will be able to drag and drop locally as well.
+
+If you want to create a large background image for your map you can make it using OpenRPG's whiteboard features or by loading many dungeon "tile" images and then save the entire map as a .jpg file. 
+
+Locking a miniature means that it is ignored when you click around the map. Useful for images of terrain or objects.
+
+Hold down Ctrl to select or right-click a locked miniature on the map. On a Mac use the Command / Apple button.
+
+OpenRPG's main four windows are all sizeable, movable and dockable. In addition by editing the layout.xml file you can put two or more of them on a tab.
+
+You can customise OpenRPG's behaviour in four ways: plugins, custom die rollers, game system specific nodes and by using filters.
+
+OpenRPG is not written for any one role playing system, but custom features have been written to aid game play for about a dozen systems. Ask around to see what might be availble, and if nothing is, consider creating your own.
+
+OpenRPG automatically saves an html log of your entire game session and saves it in the folder myfiles/logs
+
+Thanks for selecting the Traipse distribution of OpenRPG. Traipse users are growing in number and often express joy about the stability of the software. If you see a bug, any bug, please report it with the Debug Console in Traipse Suite.
+
+Die roller notes are available on the Features Node. Right click on the top of the game tree, "Insert features Node" and double click on "Load Die Roller Notes"
+
+You can search your chat session by opening the text view of it (click the button to the right of the dice). Type in the search term and hit "find".
+
+The map has a tape measure. Hold down SHIFT and drag with the left mouse button down.
--- a/orpg/chat/chat_util.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/chat/chat_util.py	Mon Nov 23 03:36:26 2009 -0600
@@ -3,7 +3,7 @@
 import re
 import string
 from orpg.orpgCore import *
-from orpg.tools.orpg_log import logger
+from orpg.tools.orpg_log import logger, debug
 from orpg.tools.decorators import debugging
 
 #============================================
@@ -19,7 +19,7 @@
 #
 # Created 04-25-2005 by Snowdog
 #=============================================
-@debugging
+
 def simple_html_repair(string):
     "Returns string with extra > symbols to isolate badly formated HTML"
     #walk though string checking positions of < and > tags.
@@ -70,10 +70,10 @@
     diff = string.count('<') - string.count('>')
     if diff > 0:
         for d in range(1,diff):
-            string = string+">"
+            string = string+">"
     return string
 
-""" Depricated! Might as well use the already made component.get('xml')
+# Depricated! Might as well use the already made component.get('xml')
 def strip_unicode(txt):
     for i in xrange(len(txt)):
         if txt[i] not in string.printable:
@@ -81,8 +81,7 @@
                 txt = txt.replace(txt[i], '&#' + str(ord(txt[i])) + ';')
             except:
                 txt = txt.replace(txt[i], '{?}')
-    return txt
-"""
+    return txt
 
 #================================================
 # strip_script_tags(string)
@@ -90,7 +89,7 @@
 # removes all script tags (start and end)
 # 04-26-2005 Snowdog
 #================================================
-@debugging
+
 def strip_script_tags(string):
     #kill the <script> issue
     p = re.compile( '<(\s*)(/*)[Ss][Cc][Rr][Ii][Pp][Tt](.*?)>')
@@ -103,7 +102,7 @@
 # removes all li tags (start and end)
 # 05-13-2005
 #================================================
-@debugging
+
 def strip_li_tags(string):
     #kill the <li> issue
     string = re.sub( r'<(\s*)[Ll][Ii](.*?)>', r'<b><font color="#000000" size=+1>*</font></b>    ', string)
@@ -118,10 +117,10 @@
 #   through legitimate means such as the OpenRPG settings.
 # 07-27-2005 by mDuo13
 #================================================
-@debugging
+
 def strip_body_tags(string):
     bodytag_regex = re.compile(r"""<\/?body.*?>""", re.I)
-    string = re.sub(bodytag_regex, "", string)
+    string = re.sub(bodytag_regex, "", string)
     return string
 
 #================================================
@@ -137,7 +136,7 @@
 # used legitimately without causing much annoyance.
 # 07-27-2005 mDuo13
 #================================================
-@debugging
+
 def strip_misalignment_tags(string):
     alignment_regex = re.compile(r"""<p([^>]*?)align\s*=\s*('.*?'|".*?"|[^\s>]*)(.*?)>""", re.I)
     string = re.sub(alignment_regex, "<p\\1\\3>", string)
@@ -148,7 +147,7 @@
     num_endcentertags = endcenter_regex.findall(string)
     if num_centertags > num_endcentertags:
         missing_tags = len(num_centertags) - len(num_endcentertags)
-        string = string + missing_tags*"</center>"#yes, you can do this.
+        string = string + missing_tags*"</center>"#yes, you can do this.
     return string
 
 #================================================
@@ -158,7 +157,7 @@
 # 05-13-2005
 # redone 07-11-2005 by mDuo13
 #================================================
-@debugging
+
 def strip_img_tags(string):
     #This is a Settings definable feature, Allowing users to enable or disable image display to fix the client crash due to large img posted to chat.
     #p = re.sub( r'<(\s*)(/*)[Ii][Mm][Gg][ ][Ss][Rr][Cc][=](.*?)>', r'<!-- img tag removed //--> <a href=\3>\3</a>', string)
--- a/orpg/chat/chatwnd.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/chat/chatwnd.py	Mon Nov 23 03:36:26 2009 -0600
@@ -228,7 +228,7 @@
         return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize())
 
 # class chat_html_window - end
-if NEWCHAT:
+if NEWCHAT:
     class ChatHtmlWindow(wx.webview.WebView):
         
         def __init__(self, parent, id):
@@ -241,23 +241,18 @@
             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)
 
-        
-        def AppendToPage(self, htmlstring):
+        def AppendToPage(self, htmlstring):
             self.SetPageSource(self.GetPageSource() + htmlstring)
 
-        
         def GetFont(self):
             return self.__font
 
-        
         def CalculateAllFonts(self, defaultsize):
             return
 
-        
         def SetDefaultFontAndSize(self, fontname, fontsize):
             self.__font = wx.Font(int(fontsize), 
                             wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, 
@@ -267,22 +262,18 @@
             return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize())
 
         #Events
-        
         def OnLinkClicked(self, linkinfo):
             href = linkinfo.GetHref()
             wb = webbrowser.get()
             wb.open(href)
 
-        
         def onPopup(self, evt):
             self.PopupMenu(self.menu)
 
-        
         def LeftUp(self, event):
             event.Skip()
             wx.CallAfter(self.parent.set_chat_text_focus, None)
 
-        
         def OnM_EditCopy(self, evt):
             wx.TheClipboard.UsePrimarySelection(False)
             wx.TheClipboard.Open()
@@ -290,30 +281,25 @@
             wx.TheClipboard.Close()
 
         #Cutom Methods
-        
         def Header(self):
             return "<html><head><style>body {font-size: " + str(self.GetFont().GetPointSize()) + "px;font-family: " + self.GetFont().GetFaceName() + ";color: " + self.parent.textcolor + ";background-color: " + self.parent.bgcolor + ";margin: 0;padding: 0 0;height: 100%;}</style></head><body>"
 
-        
         def StripHeader(self):
             tmp = self.GetPageSource().split('<BODY>')
             if tmp[-1].find('<body>') > -1: tmp = tmp[-1].split('<body>')
             return tmp[-1]
 
-        
         def build_menu(self):
             self.menu = wx.Menu()
             item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy")
             self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item)
             self.menu.AppendItem(item)
 
-        
         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()))
@@ -379,7 +365,6 @@
             self.create_gm_tab()
         self.SetSelection(0)
 
-    
     def get_tab_index(self, chatpanel):
         "Return the index of a chatpanel in the wxNotebook."
 
@@ -387,7 +372,6 @@
             if (self.GetPage(i) == chatpanel):
                 return i
 
-    
     def create_gm_tab(self):
         if self.GMChatPanel == None:
             self.GMChatPanel = chat_panel(self, -1, MAIN_TAB, 'gm')
@@ -395,7 +379,6 @@
             self.SetPageImage(self.GetPageCount()-1, 1)
             self.GMChatPanel.chatwnd.SetDefaultFontAndSize(self.font, self.fontsize)
 
-    
     def create_whisper_tab(self, playerid):
         "Add a new chatpanel directly connected to integer 'playerid' via whispering."
         private_tab = chat_panel(self, -1, WHISPER_TAB, playerid)
@@ -408,7 +391,6 @@
         wx.CallAfter(self.AliasLib.RefreshAliases)
         return private_tab
 
-    
     def create_group_tab(self, group_name):
         "Add a new chatpanel directly connected to integer 'playerid' via whispering."
         private_tab = chat_panel(self, -1, GROUP_TAB, group_name)
@@ -420,7 +402,6 @@
         wx.CallAfter(self.AliasLib.RefreshAliases)
         return private_tab
 
-    
     def create_null_tab(self, tab_name):
         "Add a new chatpanel directly connected to integer 'playerid' via whispering."
         private_tab = chat_panel(self, -1, NULL_TAB, tab_name)
@@ -432,11 +413,9 @@
         wx.CallAfter(self.AliasLib.RefreshAliases)
         return private_tab
 
-    
     def onCloseTab(self, evt):
         try: tabid = evt.GetSelection()
         except: tabid = self.GetSelection()
-
         if self.GetPageText(tabid) == 'Main Room':
             #send no close error to chat
             evt.Veto()
@@ -445,7 +424,6 @@
             msg = "Are You Sure You Want To Close This Page?"
             dlg = wx.MessageDialog(self, msg, "NotebookCtrl Question",
                                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
-
             if wx.Platform != '__WXMAC__':
                 dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False))
 
@@ -461,16 +439,13 @@
         elif panel in self.group_tabs: self.group_tabs.remove(panel)
         elif panel in self.null_tabs: self.null_tabs.remove(panel)
 
-    
     def newMsg(self, tabid):
         if tabid != self.GetSelection(): self.SetPageImage(tabid, 0)
 
-    
     def onPageChanging(self, event):
         """When private chattabs are selected, set the bitmap back to 'normal'."""
         event.Skip()
 
-    
     def onPageChanged(self, event):
         """When private chattabs are selected, set the bitmap back to 'normal'."""
         selected_idx = event.GetSelection()
@@ -567,7 +542,6 @@
         self.fontsize = self.chatwnd.GetFont().GetPointSize()
         self.scroll_down()
 
-    
     def set_default_font(self, fontname=None, fontsize=None):
         """Set all chatpanels to new default fontname/fontsize. 
         Returns current font settings in a (fontname, fontsize) tuple."""
@@ -581,7 +555,6 @@
         self.fontsize = newfontsize
         return (self.font, self.fontsize)
 
-    
     def build_menu(self):
         top_frame = component.get('frame')
         menu = wx.Menu()
@@ -673,54 +646,44 @@
         top_frame.mainmenu.Insert(2, menu, '&Chat')
 
     ## Settings Menu Events
-    
     def OnMB_ShowImages(self, event):
         if event.IsChecked(): self.settings.set_setting("Show_Images_In_Chat", '1')
         else: self.settings.set_setting("Show_Images_In_Chat", '0')
 
-    
     def OnMB_StripHTML(self, event):
-        if event.IsChecked(): self.settings.set_setting("Sstriphtml", '1')
+        if event.IsChecked(): self.settings.set_setting("striphtml", '1')
         else: self.settings.set_setting("striphtml", '0')
 
-    
     def OnMB_ChatTimeIndex(self, event):
         if event.IsChecked(): self.settings.set_setting("Chat_Time_Indexing", '1')
         else: self.settings.set_setting("Chat_Time_Indexing", '0')
 
-    
     def OnMB_ChatAutoComplete(self, event):
         if event.IsChecked(): self.settings.set_setting("SuppressChatAutoComplete", '0')
         else: self.settings.set_setting("SuppressChatAutoComplete", '1')
 
-    
     def OnMB_ShowIDinChat(self, event):
         if event.IsChecked(): self.settings.set_setting("ShowIDInChat", '1')
         else: self.settings.set_setting("ShowIDInChat", '0')
 
-    
     def OnMB_LogTimeIndex(self, event):
         if event.IsChecked(): self.settings.set_setting("TimeStampGameLog", '1')
         else: self.settings.set_setting("TimeStampGameLog", '0')
 
-    
     def OnMB_TabbedWhispers(self, event):
         if event.IsChecked(): self.settings.set_setting("tabbedwhispers", '1')
         else: self.settings.set_setting("tabbedwhispers", '0')
 
-    
     def OnMB_GMTab(self, event):
         if event.IsChecked():
             self.settings.set_setting("GMWhisperTab", '1')
             self.parent.create_gm_tab()
         else: self.settings.set_setting("GMWhisperTab", '0')
 
-    
     def OnMB_GroupWhisperTabs(self, event):
         if event.IsChecked(): self.settings.set_setting("GroupWhisperTab", '1')
         else: self.settings.set_setting("GroupWhisperTab", '0')
 
-    
     def OnMB_DiceBar(self, event):
         act = '0'
         if event.IsChecked():
@@ -734,7 +697,6 @@
         for panel in self.parent.group_tabs: panel.toggle_dice(act)
         for panel in self.parent.null_tabs: panel.toggle_dice(act)
 
-    
     def OnMB_FormatButtons(self, event):
         act = '0'
         if event.IsChecked():
@@ -749,7 +711,6 @@
         for panel in self.parent.group_tabs: panel.toggle_formating(act)
         for panel in self.parent.null_tabs: panel.toggle_formating(act)
 
-    
     def OnMB_AliasTool(self, event):
         act = '0'
         if event.IsChecked():
@@ -763,7 +724,6 @@
         for panel in self.parent.group_tabs: panel.toggle_alias(act)
         for panel in self.parent.null_tabs:panel.toggle_alias(act)
 
-    
     def OnMB_BackgroundColor(self, event):
         top_frame = component.get('frame')
         hexcolor = self.get_color()
@@ -842,7 +802,7 @@
         self.basesizer = wx.BoxSizer(wx.VERTICAL)
         self.basesizer.Add( self.chatwnd, 1, wx.EXPAND )
         self.basesizer.Add( self.toolbar_sizer, 0, wx.EXPAND )
-        self.basesizer.Add( self.chattxt, 0, wx.EXPAND )
+        self.basesizer.Add( self.chattxt, 0, wx.EXPAND )
         self.SetSizer(self.basesizer)
         self.SetAutoLayout(True)
         self.Fit()
@@ -874,7 +834,6 @@
         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)
         self.scroll_lock = None
@@ -896,14 +855,16 @@
 
     
     def build_alias(self):
-        self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL) ## Future ## Add these to a sizer, then turn the toolbar_sizer into a grid so these can adjust to the frame.
+        self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
         self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName])
         self.aliasButton = createMaskedButton( self, dir_struct["icon"] + 'player.gif', 
-                                            'Refresh list of aliases from Game Tree', wx.ID_ANY, '#bdbdbd' )
+                                            'Refresh list of aliases from Game Tree', 
+                                            wx.ID_ANY, '#bdbdbd' )
         self.aliasList.SetSelection(0)
         self.filterList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultFilterName])
         self.filterButton = createMaskedButton( self, dir_struct["icon"] + 'add_filter.gif', 
-                                             'Refresh list of filters from Game Tree', wx.ID_ANY, '#bdbdbd' )
+                                             'Refresh list of filters from Game Tree', 
+                                             wx.ID_ANY, '#bdbdbd' )
         self.filterList.SetSelection(0)
 
         self.aliasSizer.Add( self.aliasButton, 0, wx.EXPAND )
@@ -915,7 +876,6 @@
 
         if self.settings.get_setting('AliasTool_On') == '0': self.toggle_alias('0')
         else: self.toggle_alias('1')
-
     
     def toggle_alias(self, act):
         if act == '0': self.toolbar_sizer.Show(self.aliasSizer, False)
@@ -926,79 +886,62 @@
         self.textpop_lock = createMaskedButton(self, dir_struct["icon"]+'note.gif', 'Open Text View Of Chat Session', wx.ID_ANY, '#bdbdbd')
 
     
-    def build_dice(self):
-        self.numDieText = wx.TextCtrl( self, wx.ID_ANY, "1", size= wx.Size(25, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() )
-        self.dieModText = wx.TextCtrl( self, wx.ID_ANY, "", size= wx.Size(50, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() )
+    def build_dice(self):
+        self.diceSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.numDieText = wx.TextCtrl( self, wx.ID_ANY, "1", 
+                                    size= wx.Size(25, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() )
+        self.dieModText = wx.TextCtrl( self, wx.ID_ANY, "", 
+                                    size= wx.Size(50, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() )
         self.d4Button = createMaskedButton(self, dir_struct["icon"]+'b_d4.gif', 'Roll d4', wx.ID_ANY)
         self.d6Button = createMaskedButton(self, dir_struct["icon"]+'b_d6.gif', 'Roll d6', wx.ID_ANY)
         self.d8Button = createMaskedButton(self, dir_struct["icon"]+'b_d8.gif', 'Roll d8', wx.ID_ANY)
         self.d10Button = createMaskedButton(self, dir_struct["icon"]+'b_d10.gif', 'Roll d10', wx.ID_ANY)
         self.d12Button = createMaskedButton(self, dir_struct["icon"]+'b_d12.gif', 'Roll d12', wx.ID_ANY)
         self.d20Button = createMaskedButton(self, dir_struct["icon"]+'b_d20.gif', 'Roll d20', wx.ID_ANY)
-        self.d100Button = createMaskedButton(self, dir_struct["icon"]+'b_d100.gif', 'Roll d100', wx.ID_ANY)
-        self.toolbar_sizer.Add( self.numDieText, 0, wx.ALIGN_CENTER | wx.EXPAND)
-        self.toolbar_sizer.Add( self.d4Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d6Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d8Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d10Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d12Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d20Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.d100Button, 0 ,wx.EXPAND)
-        self.toolbar_sizer.Add( self.dieModText, 0, wx.ALIGN_CENTER, 5 )
+        self.d100Button = createMaskedButton(self, dir_struct["icon"]+'b_d100.gif', 'Roll d100', wx.ID_ANY)
+
+        self.diceSizer.Add( self.numDieText, 0, wx.ALIGN_CENTER | wx.EXPAND)
+        self.diceSizer.Add( self.d4Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d6Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d8Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d10Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d12Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d20Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.d100Button, 0 ,wx.EXPAND)
+        self.diceSizer.Add( self.dieModText, 0, wx.ALIGN_CENTER, 5 )
+
+        self.toolbar_sizer.Add( self.diceSizer, 0, wx.EXPAND)
         if self.settings.get_setting('DiceButtons_On') == '0': self.toggle_dice('0')
         else: self.toggle_dice('1')
 
     
     def toggle_dice(self, act):
-        if act == '0':
-            self.toolbar_sizer.Show(self.numDieText, False)
-            self.toolbar_sizer.Show(self.d4Button, False)
-            self.toolbar_sizer.Show(self.d6Button, False)
-            self.toolbar_sizer.Show(self.d8Button, False)
-            self.toolbar_sizer.Show(self.d10Button, False)
-            self.toolbar_sizer.Show(self.d12Button, False)
-            self.toolbar_sizer.Show(self.d20Button, False)
-            self.toolbar_sizer.Show(self.d100Button, False)
-            self.toolbar_sizer.Show(self.dieModText, False)
-            self.toolbar_sizer.Layout()
-        else:
-            self.toolbar_sizer.Show(self.numDieText, True)
-            self.toolbar_sizer.Show(self.d4Button, True)
-            self.toolbar_sizer.Show(self.d6Button, True)
-            self.toolbar_sizer.Show(self.d8Button, True)
-            self.toolbar_sizer.Show(self.d10Button, True)
-            self.toolbar_sizer.Show(self.d12Button, True)
-            self.toolbar_sizer.Show(self.d20Button, True)
-            self.toolbar_sizer.Show(self.d100Button, True)
-            self.toolbar_sizer.Show(self.dieModText, True)
-            self.toolbar_sizer.Layout()
+        if act == '0': self.toolbar_sizer.Show(self.diceSizer, False)
+        else: self.toolbar_sizer.Show(self.diceSizer, True)
+        self.toolbar_sizer.Layout()
 
     
-    def build_formating(self):
+    def build_formating(self):
+        self.formatSizer = wx.BoxSizer(wx.HORIZONTAL)
         self.boldButton = createMaskedButton( self, dir_struct["icon"]+'bold.gif', 
                                                             'Make the selected text Bold', wx.ID_ANY, '#bdbdbd')
         self.italicButton = createMaskedButton( self, dir_struct["icon"]+'italic.gif', 
                                                             'Italicize the selected text', wx.ID_ANY, '#bdbdbd' )
         self.underlineButton = createMaskedButton( self, dir_struct["icon"]+'underlined.gif', 
-                                                            'Underline the selected text', wx.ID_ANY, '#bdbdbd' )
-        self.toolbar_sizer.Add( self.boldButton, 0, wx.EXPAND )
-        self.toolbar_sizer.Add( self.italicButton, 0, wx.EXPAND )
-        self.toolbar_sizer.Add( self.underlineButton, 0, wx.EXPAND )
+                                                            'Underline the selected text', wx.ID_ANY, '#bdbdbd' )
+
+        self.formatSizer.Add( self.boldButton, 0, wx.EXPAND )
+        self.formatSizer.Add( self.italicButton, 0, wx.EXPAND )
+        self.formatSizer.Add( self.underlineButton, 0, wx.EXPAND )
+        self.toolbar_sizer.Add( self.formatSizer, 0, wx.EXPAND )
         if self.settings.get_setting('FormattingButtons_On') == '0': self.toggle_formating('0')
         else: self.toggle_formating('1')
 
     
     def toggle_formating(self, act):
-        if act == '0':
-            self.toolbar_sizer.Show(self.boldButton, False)
-            self.toolbar_sizer.Show(self.italicButton, False)
-            self.toolbar_sizer.Show(self.underlineButton, False)
-            self.toolbar_sizer.Layout()
-        else:
-            self.toolbar_sizer.Show(self.boldButton, True)
-            self.toolbar_sizer.Show(self.italicButton, True)
-            self.toolbar_sizer.Show(self.underlineButton, True)
-            self.toolbar_sizer.Layout()
+        if act == '0': self.toolbar_sizer.Show(self.formatSizer, False)
+        else: self.toolbar_sizer.Show(self.formatSizer, True)
+        self.toolbar_sizer.Layout()
 
     # Heroman - Ideally, we would use static labels...
     
@@ -1075,7 +1018,7 @@
         if self.lastSend:                          #  This will be zero when not typing, so equiv to if is_typing
             thisTime = time.time()                 #  thisTime is a local temp variable
             if (thisTime - self.lastPress) > 4:    #  Check to see if it's been 5 seconds since our last keystroke
-                                               #    If we're not already typing, then self.lastSend will be 0
+                                                   #  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
@@ -1729,9 +1672,9 @@
         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.
+            # troublesome message though. Worst case is a blank line to chat.
             lineHasText = 1
-        if lineHasText:
+        if lineHasText:
             #following added by mDuo13
             if myself:
                 s2 = s
@@ -1758,8 +1701,8 @@
                 newline = "<div class='"+c+"'> " + self.TimeIndexString() + name + s + "</div>"
                 log( self.settings, c, name+s )
         else: send = False
-        newline = component.get('xml').strip_unicode(newline)
-        if self.lockscroll == 0:
+        newline = chat_util.strip_unicode(newline)
+        if self.lockscroll == 0:
             self.chatwnd.AppendToPage(newline)
             self.scroll_down()
         else: self.storedata.append(newline)
@@ -1801,7 +1744,6 @@
         s = self.NormalizeParse(s)
         self.set_colors()
         self.Post(s,send,myself)
-
     
     def NormalizeParse(self, s):
         for plugin_fname in self.activeplugins.keys():
@@ -1817,7 +1759,6 @@
             s = self.ParseFilter(s)
             self.parsed = 1
         return s
-
     
     def ParseFilter(self, s):
         s = self.GetFilteredText(s)
@@ -1833,7 +1774,6 @@
             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"""
@@ -1852,7 +1792,6 @@
                 s = s.replace("[" + matches[i] + "]", "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 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
@@ -1875,7 +1814,6 @@
 
     # This subroutine builds a chat display name.
     #
-    
     def chat_display_name(self, player):
         if self.settings.get_setting("ShowIDInChat") == "0":
             display_name = player[0]
@@ -1885,7 +1823,6 @@
 
     # This subroutine will get a hex color and return it, or return nothing
     #
-    
     def get_color(self):
         data = wx.ColourData()
         data.SetChooseFull(True)
@@ -1901,7 +1838,6 @@
             return None
     # def get_color - end
 
-    
     def replace_quotes(self, s):
         in_tag = 0
         i = 0
@@ -1926,15 +1862,108 @@
             for child in child_list:
                 if step == depth: break
                 if child.get('name') == path[step]:
-                    node = child
-                    step += 1
-                    self.resolve_loop(node, path, step, depth)
+                    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(cell[0])].findall('cell')
+        self.data = col[int(cell[1])].text or 'No Cell Data!'
+        return
+
+    def resolve_cust_loop(self, node, path, step, depth):
+        node_class = node.get('class')
+        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 = 0
+            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 = 0
+            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]):
+            if step+1 == depth: self.data = pc_stats[path[step]][0] + ' +('+pc_stats[path[step]][1]+')'
+            elif path[step+1].lower() == 'mod': self.data = pc_stats[path[step]][1]
+            elif path[step+1].lower() == 'check': self.data = '<b>'+path[step]+' Check:</b> [1d20+'+str(pc_stats[path[step]][1])+']'
+            return
 
     def resolution(self, node):
         if self.passed == False:
             self.passed = True
             if node.get('class') == 'textctrl_handler': self.data = str(node.find('text').text)
-            else: self.data = 'Nodehandler for '+ node.get('class') + ' not done!' or 'No Data!'
+            else: self.data = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
         else:
             self.data = ''
             pass
@@ -1945,7 +1974,6 @@
         cur_loc = 0
         reg = re.compile("(!!(.*?)!!)")
         matches = reg.findall(s)
-        print matches
         for i in xrange(0,len(matches)):
             newstr = txt = '!@' + node.get('map') + '::' + matches[i][1] + '@!'
             s = s.replace(matches[i][0], newstr, 1)
@@ -1954,13 +1982,13 @@
 
     def resolve_nodes(self, s):
         self.passed = False
-        self.data = 'No Data!'
+        self.data = 'Invalid Reference!'
         value = ""
         path = s.split('::')
         depth = len(path)
-        self.gametree = component.get('tree')
-        dom = self.gametree.xml_root.getchildren()
-        for node in dom:
-            if node.get('name') == path[0]:
-                self.resolve_loop(node, path, 1, len(path))
+        self.gametree = component.get('tree')
+        node = self.gametree.tree_map[path[0]]['node']
+        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
--- a/orpg/gametree/gametree.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/gametree/gametree.py	Mon Nov 23 03:36:26 2009 -0600
@@ -109,7 +109,7 @@
         self.id = 1
         self.dragging = False
         self.last_save_dir = dir_struct["user"]
-        self.tree_map = []
+        self.tree_map = {}
 
         #Create tree from default if it does not exist
         validate.config_file("tree.xml","default_tree.xml")
@@ -409,7 +409,7 @@
             type = f.GetFilterIndex()
             with open(f.GetPath(),"w") as f:
                 data = "<html><head><title>"+obj.xml.get("name")+"</title></head>"
-                data += "<body bgcolor=\"#FFFFFF\" >"+obj.tohtml()+"</body></html>"
+                data += "<body bgcolor='#FFFFFF' >"+obj.tohtml()+"</body></html>"
                 for tag in ("</tr>","</td>","</th>","</table>","</html>","</body>"):
                     data = data.replace(tag,tag+"\n")
                 f.write(data)
@@ -479,7 +479,7 @@
         obj = self.GetPyData(item)
         name = "New " + obj.xml_root.get("name")
         icon = obj.xml_root.get("icon")
-        xml_data = "<nodehandler name=\""+name+"\" icon=\"" + icon + "\" module=\"core\" class=\"node_loader\" >"
+        xml_data = "<nodehandler name='"+name+"' icon='" + icon + "' module='core' class='node_loader' >"
         xml_data += xml.toxml(obj)
         xml_data += "</nodehandler>"
         self.insert_xml(xml_data)
@@ -687,6 +687,9 @@
         return family_tree
     
     def load_xml(self, xml_element, parent_node, prev_node=None):
+        if parent_node == self.root:
+            self.tree_map[xml_element.get('name')] = {}
+            self.tree_map[xml_element.get('name')]['node'] = xml_element
         if parent_node != self.root:
             ## Loading XML seems to lag on Grids and Images need a cache for load speed ##
             family_tree = self.get_tree_map(parent_node)
--- a/orpg/gametree/nodehandlers/containers.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/gametree/nodehandlers/containers.py	Mon Nov 23 03:36:26 2009 -0600
@@ -160,10 +160,11 @@
 class group_edit_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
-        self.handler = handler
+        self.handler = handler
+        self.outline = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Group"), wx.VERTICAL)
+
         sizer = wx.BoxSizer(wx.VERTICAL)
-        self.text = {   P_TITLE : wx.TextCtrl(self, P_TITLE, handler.xml.get('name'))
-                      }
+        self.text = {P_TITLE : wx.TextCtrl(self, P_TITLE, handler.xml.get('name')) }
         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))
@@ -180,10 +181,10 @@
 
         sizer.Add(radio_c, 0, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
-        sizer.Add(radio_b, 0, wx.EXPAND)
-
-        self.sizer = sizer
-        self.outline = wx.StaticBox(self,-1,"Group")
+        sizer.Add(radio_b, 0, wx.EXPAND)
+
+        self.outline.Add(sizer, 0)
+        self.sizer = self.outline
         self.SetSizer(self.sizer)
         self.SetAutoLayout(True)
         self.Fit()
@@ -220,10 +221,10 @@
         container_handler.__init__(self, xml, tree_node)
 
     def get_design_panel(self,parent):
-        return tabbed_panel(parent,self,1)
+        return tabbed_edit_panel(parent, self)
 
     def get_use_panel(self,parent):
-        return tabbed_panel(parent,self,2)
+        return tabbed_panel(parent, self, 1)
 
 
 class tabbed_panel(orpgTabberWnd):
@@ -232,7 +233,6 @@
         self.handler = handler
         self.parent = parent
         handler.tree.traverse(handler.mytree_node, self.pick_panel, mode, False)
-
         parent.SetSize(self.GetBestSize())
 
     def pick_panel(self, treenode, mode):
@@ -240,7 +240,28 @@
         if mode == 1: panel = node.get_design_panel(self)
         else: panel = node.get_use_panel(self)
         name = node.xml.get("name")
-        if panel: self.AddPage(panel, name, False)
+        if panel: self.AddPage(panel, name, False)
+
+class tabbed_edit_panel(orpgTabberWnd):
+    def __init__(self, parent, handler):
+        orpgTabberWnd.__init__(self, parent, style=FNB.FNB_NO_X_BUTTON)
+        self.handler = handler
+        self.parent = parent
+        main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Tabber"), wx.VERTICAL)
+        self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
+        main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        main_sizer.Add(self.title, 0, wx.EXPAND)
+        self.SetSizer(main_sizer)
+        self.SetAutoLayout(True)
+        self.Fit()
+        self.Bind(wx.EVT_TEXT, self.on_text, id=1)
+
+    def on_text(self,evt):
+        txt = self.title.GetValue()
+        if txt != "":
+            self.handler.xml.set('name',txt)
+            self.handler.rename(txt)
+
 
 #################################
 ## Splitter container
@@ -258,10 +279,6 @@
             if child_xml.tag == "splitter_atts": self.xml.remove(child_xml) #Same here!
             elif child_xml: self.tree.load_xml(child_xml,self.mytree_node)
         if not self.xml.get('horizontal'): self.xml.set('horizontal', '0')
-        """if not self.atts:
-            self.atts = Element('splitter_atts')
-            self.atts.set("horizontal","0")
-            self.xml.append(self.atts)"""
 
     def get_design_panel(self,parent):
         return self.build_splitter_wnd(parent, 1)
@@ -275,27 +292,16 @@
 
     def build_splitter_wnd(self, parent, mode):
         self.split = self.xml.get("horizontal")
-
         self.pane = splitter_panel(parent, self)
-
-        self.splitter = MultiSplitterWindow(self.pane, -1, style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH|wx.SP_NO_XP_THEME)
-
-        if self.split == '1':
-            self.splitter.SetOrientation(wx.VERTICAL)
-        else:
-            self.splitter.SetOrientation(wx.HORIZONTAL)
-
+        self.splitter = MultiSplitterWindow(self.pane, -1, 
+                        style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH|wx.SP_NO_XP_THEME)
+        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()
-
+        if mode != 1: self.pane.hozCheck.Hide()
         self.pane.SetSize((self.bestSizex, self.bestSizey))
         self.pane.Layout()
         parent.SetSize(self.pane.GetSize())
@@ -305,7 +311,6 @@
         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
@@ -316,9 +321,7 @@
             self.bestSizex += sash
             if self.bestSizey < tmp.GetBestSize()[1]:
                 self.bestSizey = tmp.GetBestSize()[1]+31
-
         self.splitter.AppendWindow(tmp, sash)
-
     def get_size_constraint(self):
         return 1
 
@@ -327,17 +330,16 @@
         wx.Panel.__init__(self, parent, -1)
         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")
 
-        if hoz == '1':
-            self.hozCheck.SetValue(True)
-            #self.splitsize = wx.BoxSizer(wx.HORIZONTAL)
-        else:
-            self.hozCheck.SetValue(False)
-            #self.splitsize = wx.BoxSizer(wx.VERTICAL)
-
+        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))
         #sizer.Add(self.splitsize,  1, wx.EXPAND)
@@ -345,12 +347,17 @@
         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())
 
     def on_check_box(self,evt):
         state = self.hozCheck.GetValue()
-        if state:
-            self.handler.xml.set("horizontal", "1")
-        else:
-            self.handler.xml.set("horizontal", "0")
+        if state: self.handler.xml.set("horizontal", "1")
+        else: self.handler.xml.set("horizontal", "0")
+
+    def on_text(self,evt):
+        txt = self.title.GetValue()
+        if txt != "":
+            self.handler.xml.set('name',txt)
+            self.handler.rename(txt)
+
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Mon Nov 23 03:36:26 2009 -0600
@@ -29,7 +29,7 @@
 __version__ = "$Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $"
 
 from core import *
-from forms import *
+from forms import *
 
 class rpg_grid_handler(node_handler):
     """ Node handler for rpg grid tool
@@ -390,7 +390,7 @@
         num = self.GetNumberRows()
         if num == 1:
             return
-        self.handler.grid.remove(self.handler.grid[num-1])#always remove last row -- nasty
+        self.handler.grid.remove(self.handler.grid[num-1])# always remove last row -- nasty
         self.DeleteRows(num-1,1)
         self.rows = self.handler.grid.findall('row')
         self.handler.refresh_rows()
@@ -401,7 +401,7 @@
             return
         for r in self.rows:
             cells = r.findall('cell')
-            r.remove(r[num-1])# always remove the last column -- nasty
+            r.remove(r[num-1])                  # always remove the last column -- nasty
         self.DeleteCols(num-1,1)
         self.set_col_widths()
 
@@ -433,37 +433,36 @@
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
-        self.grid = rpg_grid(self,handler)
-        self.title = wx.TextCtrl(self, G_TITLE, handler.xml.get('name'))
+        self.grid = rpg_grid(self,handler)
+        self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Grid"), wx.VERTICAL)
 
+        self.title = wx.TextCtrl(self, G_TITLE, handler.xml.get('name'))
+
         radio_b = wx.RadioBox(self, GRID_BOR, "Border (HTML)", choices=["no","yes"])
-        border = handler.grid.get("border")
+        border = handler.grid.get("border")
         radio_b.SetSelection(int(border))
 
-        self.auto_size = wx.CheckBox(self, G_AUTO_SIZE, " Auto Size")
-        if handler.is_autosized() == '1':
-            self.auto_size.SetValue(True)
-        else:
-            self.auto_size.SetValue(False)
+        self.auto_size = wx.CheckBox(self, G_AUTO_SIZE, "Auto Size")
+        if handler.is_autosized() == '1': self.auto_size.SetValue(True)
+        else: self.auto_size.SetValue(False)
 
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
         sizer.Add(wx.Button(self, G_ADD_ROW, "Add Row"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
         sizer.Add(wx.Button(self, G_DEL_ROW, "Remove Row"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
         sizer.Add(wx.Button(self, G_ADD_COL, "Add Column"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Button(self, G_DEL_COL, "Remove Column"), 1, wx.EXPAND)
+        sizer.Add(wx.Button(self, G_DEL_COL, "Remove Column"), 1, wx.EXPAND)
 
-        self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"Grid"), wx.VERTICAL)
         self.main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
         self.main_sizer.Add(self.title, 0, wx.EXPAND)
         self.main_sizer.Add(radio_b, 0, 0)
         self.main_sizer.Add(self.auto_size, 0, 0)
         self.main_sizer.Add(self.grid,1,wx.EXPAND)
-        self.main_sizer.Add(sizer,0,wx.EXPAND)
+        self.main_sizer.Add(sizer,0,wx.EXPAND)
 
-        self.SetSizer(self.main_sizer)
+        self.SetSizer(self.main_sizer)
         self.SetAutoLayout(True)
         self.Fit()
 
--- a/orpg/main.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/main.py	Mon Nov 23 03:36:26 2009 -0600
@@ -135,6 +135,13 @@
         logger.debug("plugins reloaded and startup plugins launched")
         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
+        tipotday_start = settings.get('tipotday_start')
+        try: tipotday_start = int(tipotday_start)
+        except TypeError: tipotday_start = 0
+
+
+        self.TipOfTheDay = wx.CreateFileTipProvider(dir_struct['data']+'tips.txt', tipotday_start)
+
         #Load Update Manager
         component.add('updatemana', self.updateMana)
         logger.debug("update manager reloaded")
@@ -145,23 +152,37 @@
         logger.debug("debugger window")
         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
+    def ShowTipOfTheDay(self):
+        if wx.ShowTip(self, self.TipOfTheDay, settings.get('tipotday_enabled') != '0'):
+            settings.change('tipotday_enabled', '1')
+        else: settings.change('tipotday_enabled', '0')
+        settings.change('tipotday_start', str(self.TipOfTheDay.CurrentTip))
     
     def post_show_init(self):
-        """Some Actions need to be done after the main fram is drawn"""
+        """Some Actions need to be done after the main frame is drawn"""
         self.players.size_cols()
+        try:
+            if settings.get('tipotday_enabled').lower() != '0': self.ShowTipOfTheDay()
+        except: self.add_setting('Tip of the Day')
 
-    
+
+    def add_setting(self, setting):
+        if setting == 'Tip of the Day':
+            settings.add_tab('General', 'Tip of the Day', 'grid')
+            settings.add('Tip of the Day', 'tipotday_start', '0', 'int', 'Current Tip of the Day')
+            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')
+
     def get_activeplugins(self):
         try: tmp = self.pluginsFrame.get_activeplugins()
         except: tmp = {}
         return tmp
-
     
     def get_startplugins(self):
         try: tmp = self.pluginsFrame.get_startplugins()
         except: tmp = {}
         return tmp
-
     
     def on_password_signal(self,signal,type,id,data):
         try:
@@ -233,7 +254,8 @@
                     ['  &About'],
                     ['  Online User Guide'],
                     ['  Change Log'],
-                    ['  Report a Bug']
+                    ['  Report a Bug'],
+                    ['  Tip of the Day']
                 ]]
 
         self.mainmenu = MenuBarEx(self, menu)
@@ -606,6 +628,9 @@
         wb = webbrowser.get()
         wb.open("http://www.assembla.com/spaces/tickets/index/traipse_dev?spaces_tool_id=Tickets")
 
+    def OnMB_HelpTipoftheDay(self):
+        self.ShowTipOfTheDay()
+
 
     #################################
     ##    Build the GUI
@@ -762,8 +787,7 @@
         self.Thaw()
 
     
-    def do_tab_window(self,xml_dom,parent_wnd):
-    #def do_tab_window(self, etreeEl, parent_wnd):
+    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)
 
@@ -772,12 +796,6 @@
             wnd = self.build_window(c,temp_wnd)
             name = c.get("name")
             temp_wnd.AddPage(wnd, name, False)
-
-        """
-        for c in etreeEl.getchildren():
-            wnd = self.build_window(c, temp_wnd)
-            temp_wnd.AddPage(wnd, c.get('name'), False)
-        """
         return temp_wnd
 
     
--- a/orpg/mapper/background.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/background.py	Mon Nov 23 03:36:26 2009 -0600
@@ -50,7 +50,7 @@
 BG_COLOR = 3
 
 class layer_back_ground(layer_base):
-    @debugging
+
     def __init__(self, canvas):
         self.canvas = canvas
         self.log = component.get('log')
@@ -59,14 +59,14 @@
         self.r_h = RGBHex()
         self.clear()
 
-    @debugging
+
     def error_loading_image(self, image):
         msg = "Unable to load image:" + `image`
         dlg = wx.MessageDialog(self.canvas,msg,'File not Found',wx.ICON_EXCLAMATION)
         dlg.ShowModal()
         dlg.Destroy()
 
-    @debugging
+
     def clear(self):
         self.type = BG_NONE
         self.bg_bmp = None
@@ -77,16 +77,16 @@
         self.localTime = -1
         self.isUpdated = True
 
-    @debugging
+
     def get_type(self):
         return self.type
 
-    @debugging
+
     def get_img_path(self):
         if self.img_path: return self.img_path
         else: return ""
 
-    @debugging
+
     def get_color(self):
         hexcolor = "#FFFFFF"
         if self.bg_color:
@@ -94,25 +94,25 @@
             hexcolor = self.r_h.hexstring(red, green, blue)
         return hexcolor
 
-    @debugging
+
     def set_texture(self, path):
         self.isUpdated = True
         self.type = BG_TEXTURE
         if self.img_path != path:
             try:
-                self.bg_bmp = ImageHandler.load(path, "texture", 0)
+                self.bg_bmp = ImageHandler.load(path, "texture", 0).ConvertToBitmap()
                 if self.bg_bmp == None:
                     logger.general("Invalid image type!")
                     raise Exception, "Invalid image type!"
             except: self.error_loading_image(path)
         self.img_path = path
 
-    @debugging
+
     def set_image(self, path, scale):
         self.isUpdated = True
         self.type = BG_IMAGE
         if self.img_path != path:
-            self.bg_bmp = ImageHandler.load(path, "background", 0)
+            self.bg_bmp = ImageHandler.load(path, "background", 0).ConvertToBitmap()
             try:
                 if self.bg_bmp == None:
                     logger.general("Invalid image type!")
@@ -121,7 +121,7 @@
         self.img_path = path
         return (self.bg_bmp.GetWidth(),self.bg_bmp.GetHeight())
 
-    @debugging
+
     def set_color(self, color):
         self.isUpdated = True
         self.type = BG_COLOR
@@ -129,17 +129,11 @@
         self.bg_color = cmpColour(r,g,b)
         self.canvas.SetBackgroundColour(self.bg_color)
 
-    @debugging
+
     def layerDraw(self, dc, scale, topleft, size):
         if self.bg_bmp == None or not self.bg_bmp.Ok() or ((self.type != BG_TEXTURE) and (self.type != BG_IMAGE)):
             return False
         dc2 = wx.MemoryDC()
-        
-        ### Temporary ###
-        try: self.bg_bmp = self.bg_bmp.ConvertToBitmap()
-        except: pass
-        #################
-        
         dc2.SelectObject(self.bg_bmp)
         topLeft = [int(topleft[0]/scale), int(topleft[1]/scale)]
         topRight = [int((topleft[0]+size[0]+1)/scale)+1, int((topleft[1]+size[1]+1)/scale)+1]
@@ -210,7 +204,7 @@
         del dc2
         return True
 
-    @debugging
+
     def layerToXML(self, action="update"):
         xml_str = "<bg"
         if self.bg_color != None:
@@ -230,7 +224,7 @@
             return xml_str
         else: return ''
 
-    @debugging
+
     def layerTakeDOM(self, xml_dom):
         type = BG_COLOR
         color = xml_dom.getAttribute("color")
@@ -263,7 +257,7 @@
                 postdata = urllib.urlencode({'filename':filename[1], 'imgdata':imgdata, 'imgtype':imgtype})
                 thread.start_new_thread(self.upload, (postdata, self.localPath, type))
 
-    @debugging
+
     def upload(self, postdata, filename, type):
         self.lock.acquire()
         if type == 'Image' or type == 'Texture':
--- a/orpg/mapper/background_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/background_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -27,8 +27,7 @@
 #
 __version__ = "$Id: background_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
 
-from base_msg import map_element_msg_base
-from xml.etree.ElementTree import ElementTree
+from base_msg import *
 
 class bg_msg(map_element_msg_base):
 
--- a/orpg/mapper/base_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/base_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -29,16 +29,15 @@
 
 from threading import RLock
 from orpg.networking.mplay_client import *
-
-from xml.etree.ElementTree import XML, fromstring, parse
+from xml.etree.ElementTree import ElementTree, Element
 
 class map_element_msg_base:
 #  This is a base class
 
     def __init__(self,reentrant_lock_object = None):
 
-        if not self.tagname:
-            raise Exception, "This is a virtual class that cannot be directly instantiated.  Set self.tagname in derived class."; exit()
+        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
@@ -197,38 +196,46 @@
     #########################################
     #  XML importers begin
 
-    def _from_dom(self,xml,prop_func):
+    def _from_dom(self,xml_dom,prop_func):
         self.p_lock.acquire()
-        if xml.tag == self.tagname:
-            if xml.keys():
-                for k in xml.keys():
-                    prop_func(k, xml.get(k))
+        if iselement(xml_dom): ## Uses new Element Tree style
+            if xml_dom.tag == self.tagname:
+                if xml_dom.attrib:
+                    for k in xml_dom.attrib:
+                        prop_func(k,xml_dom.get(k))
+        elif not iselement(xml_dom): ## Uses old DOM style (deprecated!!)
+            if xml_dom.tagName == self.tagname:
+                if xml_dom.getAttributeKeys():
+                    for k in xml_dom.getAttributeKeys():
+                        prop_func(k,xml_dom.getAttribute(k))
         else:
             self.p_lock.release()
             raise Exception, "Error attempting to modify a " + self.tagname + " from a non-<" + self.tagname + "/> element"
         self.p_lock.release()
 
-    def init_from_dom(self, xml):
-    #  xml must be pointing to an empty tag.  Override in a derived class for <map/> and other similar tags.
-        self._from_dom(xml,self.init_prop)
+    def init_from_dom(self,xml_dom):
+    #  xml_dom must be pointing to an empty tag.  Override in a derived class for <map/> and other similar tags.
+        self._from_dom(xml_dom,self.init_prop)
 
-    def set_from_dom(self, xml):
-    #  xml must be pointing to an empty tag.  Override in a derived class for <map/> and other similar tags
-        self._from_dom(xml, self.set_prop)
+    def set_from_dom(self,xml_dom):
+    #  xml_dom must be pointing to an empty tag.  Override in a derived class for <map/> and other similar tags
+        self._from_dom(xml_dom,self.set_prop)
 
-    def init_from_xml(self, tree):
-        #tree = XML(xmlString)
-        node_list = tree.findall(self.tagname)
+    def init_from_xml(self,xml):
+        xml_dom = parseXml(xml)
+        node_list = xml_dom.getElementsByTagName(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())
+            while len(node_list): self.init_from_dom(node_list.pop())
+        if xml_dom: xml_dom.unlink()
 
-    def set_from_xml(self, tree):
-        #tree = XML(xmlString)
-        node_list = tree.findall(self.tagname)
+    def set_from_xml(self,xml):
+        xml_dom = parseXml(xml)
+        node_list = xml_dom.getElementsByTagName(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()
+
     # XML importers end
     #########################################
--- a/orpg/mapper/fog.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/fog.py	Mon Nov 23 03:36:26 2009 -0600
@@ -83,7 +83,6 @@
         self.log = component.get('log')
         layer_base.__init__(self)
         self.color = wx.Color(128, 128, 128)
-        #if "__WXGTK__" not in wx.PlatformInfo: self.color = wx.Color(128,128,128, 128)
         self.fogregion = wx.Region()
         self.fogregion.Clear()
         self.fog_bmp = None
@@ -122,8 +121,7 @@
         self.fill_fog()
 
     def fill_fog(self):
-        if not self.use_fog:
-            return
+        if not self.use_fog: return
         mdc = wx.MemoryDC()
         mdc.SelectObject(self.fog_bmp)
         mdc.SetPen(wx.TRANSPARENT_PEN)
@@ -144,7 +142,6 @@
         if self.fog_bmp == None or not self.fog_bmp.Ok() or not self.use_fog:
             return
         if self.last_role != self.canvas.frame.session.role: self.fill_fog()
-        
         mdc = wx.MemoryDC()
         mdc.SelectObject(self.fog_bmp)
         dc.Blit(0, 0, self.canvas.size[0], self.canvas.size[1], mdc, 0, 0, wx.AND)
@@ -184,14 +181,8 @@
         regn.Clear()
         list = IRegion().scan_Convert(polypt)
         for i in list:
-            if regn.IsEmpty():
-                #if "__WXGTK__" not in wx.PlatformInfo: 
-                regn = wx.Region(i.left*COURSE, i.y*COURSE, i.right*COURSE+1-i.left*COURSE, 1*COURSE)
-                #else: regn = wx.Region(i.left, i.y, i.right+1-i.left, 1)
-            else:
-                #if "__WXGTK__" not in wx.PlatformInfo: 
-                regn.Union(i.left*COURSE, i.y*COURSE, i.right*COURSE+1-i.left*COURSE, 1*COURSE)
-                #else: regn.Union(i.left, i.y, i.right+1-i.left, 1)
+            if regn.IsEmpty(): regn = wx.Region(i.left*COURSE, i.y*COURSE, i.right*COURSE+1-i.left*COURSE, 1*COURSE)
+            else: regn.Union(i.left*COURSE, i.y*COURSE, i.right*COURSE+1-i.left*COURSE, 1*COURSE)
         return regn
 
     def add_area(self, area="", show="Yes"):
@@ -215,16 +206,10 @@
         ri = wx.RegionIterator(self.fogregion)
         if not (ri.HaveRects()): fog_string = FogArea("all", self.log).toxml("del")
         while ri.HaveRects():
-            #if "__WXGTK__" not in wx.PlatformInfo:
             x1 = ri.GetX()/COURSE
             x2 = x1+(ri.GetW()/COURSE)-1
             y1 = ri.GetY()/COURSE
             y2 = y1+(ri.GetH()/COURSE)-1
-            #else:
-            #    x1 = ri.GetX()
-            #    x2 = x1+ri.GetW()-1
-            #    y1 = ri.GetY()
-            #    y2 = y1+ri.GetH()-1
             poly = FogArea(str(x1) + "," + str(y1) + ";" +
                           str(x2) + "," + str(y1) + ";" +
                           str(x2) + "," + str(y2) + ";" +
--- a/orpg/mapper/fog_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/fog_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -27,14 +27,13 @@
 
 from base_msg import *
 from region import *
-#from orpg.minidom import Element
+from orpg.minidom import Element
 import string
-from xml.etree.ElementTree import ElementTree
 
 class fog_msg(map_element_msg_base):
 
     def __init__(self,reentrant_lock_object = None):
-        self.tag = "fog"
+        self.tagname = "fog"
         map_element_msg_base.__init__(self,reentrant_lock_object)
         self.use_fog = 0
         self.fogregion=IRegion()
@@ -42,16 +41,16 @@
 
     def get_line(self,outline,action,output_act):
         elem = Element( "poly" )
-        if ( output_act ): elem.set( "action", action )
-        if ( outline == 'all' ) or ( outline == 'none' ): elem.set( "outline", outline )
+        if ( output_act ): elem.setAttribute( "action", action )
+        if ( outline == 'all' ) or ( outline == 'none' ): elem.setAttribute( "outline", outline )
         else:
-            elem.set( "outline", "points" )
+            elem.setAttribute( "outline", "points" )
             for pair in string.split( outline, ";" ):
                 p = string.split( pair, "," )
                 point = Element( "point" )
-                point.set( "x", p[ 0 ] )
-                point.set( "y", p[ 1 ] )
-                elem.append( point )
+                point.setAttribute( "x", p[ 0 ] )
+                point.setAttribute( "y", p[ 1 ] )
+                elem.appendChild( point )
         str = elem.toxml()
         elem.unlink()
         return str
@@ -95,11 +94,11 @@
     def interpret_dom(self,xml_dom):
         self.use_fog=1
         #print 'fog_msg.interpret_dom called'
-        children = xml_dom.getchildren()
+        children = xml_dom._get_childNodes()
         #print "children",children
         for l in children:
-            action = l.get("action")
-            outline = l.get("outline")
+            action = l.getAttribute("action")
+            outline = l.getAttribute("outline")
             #print "action/outline",action, outline
             if (outline=="all"):
                 polyline=[]
@@ -110,9 +109,9 @@
                 self.fogregion.Clear()
             else:
                 polyline=[]
-                list = l.getchildren()
+                list = l._get_childNodes()
                 for node in list:
-                    polyline.append( IPoint().make( int(node.get("x")), int(node.get("y")) ) )
+                    polyline.append( IPoint().make( int(node.getAttribute("x")), int(node.getAttribute("y")) ) )
                     # pointarray = outline.split(";")
                     # for m in range(len(pointarray)):
                     #     pt=pointarray[m].split(",")
--- a/orpg/mapper/grid_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/grid_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -30,10 +30,8 @@
 from base_msg import map_element_msg_base
 #from base_msg import * ## ?? import all? Deprecated!?
 
-from xml.etree.ElementTree import ElementTree
-
 class grid_msg(map_element_msg_base):
 
     def __init__(self,reentrant_lock_object = None):
         self.tagname = "grid"
-        map_element_msg_base.__init__(self, reentrant_lock_object)
+        map_element_msg_base.__init__(self,reentrant_lock_object)
--- a/orpg/mapper/images.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/images.py	Mon Nov 23 03:36:26 2009 -0600
@@ -63,7 +63,7 @@
             if self.__fetching[path]:
                 thread.start_new_thread(self.__loadCacheThread,
                                         (path, image_type, imageId))
-        return wx.Bitmap(dir_struct["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)
+        return wx.Image(dir_struct["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)
 
     def directLoad(self, path):
         # Directly load an image, no threads
--- a/orpg/mapper/map.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/map.py	Mon Nov 23 03:36:26 2009 -0600
@@ -62,7 +62,6 @@
         self.session = component.get("session")
         wx.ScrolledWindow.__init__(self, parent, ID, 
             style=wx.HSCROLL | wx.VSCROLL | wx.FULL_REPAINT_ON_RESIZE | wx.SUNKEN_BORDER )
-        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
         self.frame = parent
         self.MAP_MODE = 1      #Mode 1 = MINI, 2 = DRAW, 3 = TAPE MEASURE
         self.layers = {}
@@ -109,15 +108,6 @@
         # miniatures drag
         self.drag = None
 
-        #self.Bind(wx.EVT_MOUSEWHEEL, self.MouseWheel)
-
-    def MouseWheel(self, evt):
-        if evt.CmdDown():
-            print evt.GetWheelRotation()
-            if evt.GetWheelRotation() > 0: self.on_zoom_in(None)
-            elif evt.GetWheelRotation() < 0: self.on_zoom_out(None)
-            else: pass
-
     def better_refresh(self, event=None):
         self.Refresh(True)
 
@@ -126,21 +116,43 @@
 
     def processImages(self, evt=None):
         self.session = component.get("session")
-        tabs = ['Background', 'Grid', 'Miniatures', 'Whiteboard', 'Fog', 'General']
         if self.session.my_role() == self.session.ROLE_LURKER or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            for tab in tabs:
-                cidx = self.parent.get_tab_index(tab)
-                self.parent.tabs.EnableTab(cidx, False)
-        elif self.session.my_role() == self.session.ROLE_PLAYER:
-            for tab in tabs:
-                cidx = self.parent.get_tab_index(tab)
-                if tab == "Miniatures" or tab == "Whiteboard": 
-                    self.parent.tabs.EnableTab(cidx, True)
-                else: self.parent.tabs.EnableTab(cidx, False)
-        elif self.session.my_role() == self.session.ROLE_GM and str(self.session.group_id) != '0':
-            for tab in tabs:
-                cidx = self.parent.get_tab_index(tab)
-                self.parent.tabs.EnableTab(cidx, True)
+            cidx = self.parent.get_tab_index("Background")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+            cidx = self.parent.get_tab_index("Grid")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+            cidx = self.parent.get_tab_index("Miniatures")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+            cidx = self.parent.get_tab_index("Whiteboard")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+            cidx = self.parent.get_tab_index("Fog")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+            cidx = self.parent.get_tab_index("General")
+            self.parent.layer_tabs.EnableTab(cidx, False)
+        else:
+            cidx = self.parent.get_tab_index("Background")
+            if not self.parent.layer_tabs.GetEnabled(cidx):
+                cidx = self.parent.get_tab_index("Miniatures")
+                self.parent.layer_tabs.EnableTab(cidx, True)
+                cidx = self.parent.get_tab_index("Whiteboard")
+                self.parent.layer_tabs.EnableTab(cidx, True)
+                cidx = self.parent.get_tab_index("Background")
+                self.parent.layer_tabs.EnableTab(cidx, False)
+                cidx = self.parent.get_tab_index("Grid")
+                self.parent.layer_tabs.EnableTab(cidx, False)
+                cidx = self.parent.get_tab_index("Fog")
+                self.parent.layer_tabs.EnableTab(cidx, False)
+                cidx = self.parent.get_tab_index("General")
+                self.parent.layer_tabs.EnableTab(cidx, False)
+                if self.session.my_role() == self.session.ROLE_GM:
+                    cidx = self.parent.get_tab_index("Background")
+                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    cidx = self.parent.get_tab_index("Grid")
+                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    cidx = self.parent.get_tab_index("Fog")
+                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    cidx = self.parent.get_tab_index("General")
+                    self.parent.layer_tabs.EnableTab(cidx, True)
         if not self.cacheSizeSet:
             self.cacheSizeSet = True
             cacheSize = component.get('settings').get_setting("ImageCacheSize")
@@ -149,15 +161,18 @@
         if not ImageHandler.Queue.empty():
             (path, image_type, imageId) = ImageHandler.Queue.get()
             img = wx.ImageFromMime(path[1], path[2])
-            # Now, apply the image to the proper object
-            if image_type == "miniature":
-                min = self.layers['miniatures'].get_miniature_by_id(imageId)
-                if min: min.set_bmp(img)
-            elif image_type == "background" or image_type == "texture":
-                self.layers['bg'].bg_bmp = img.ConvertToBitmap()
-                if image_type == "background": self.set_size([img.GetWidth(), img.GetHeight()])
+            try:
+                # Now, apply the image to the proper object
+                if image_type == "miniature":
+                    min = self.layers['miniatures'].get_miniature_by_id(imageId)
+                    if min: min.set_bmp(img)
+                elif image_type == "background" or image_type == "texture":
+                    self.layers['bg'].bg_bmp = img.ConvertToBitmap()
+                    if image_type == "background": self.set_size([img.GetWidth(), img.GetHeight()])
+            except: pass
             # Flag that we now need to refresh!
             self.requireRefresh += 1
+
             """ Randomly purge an item from the cache, while this is lamo, it does
                 keep the cache from growing without bounds, which is pretty important!"""
             if len(ImageHandler.Cache) >= self.cacheSize:
@@ -238,9 +253,6 @@
         topleft1 = self.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 = wx.AutoBufferedPaintDC(self)
             dc.SetPen(wx.TRANSPARENT_PEN)
             dc.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
@@ -256,20 +268,11 @@
             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)
         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)
@@ -707,35 +710,30 @@
         self.top_frame = component.get('frame')
         self.root_dir = os.getcwd()
         self.current_layer = 2
-        self.tabs = orpgTabberWnd(self, style=FNB.FNB_NO_X_BUTTON|FNB.FNB_BOTTOM|FNB.FNB_NO_NAV_BUTTONS)
-        self.handlers = {}
-        self.handlers[0]=(background_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[0],"Background")
-        self.handlers[1]=(grid_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[1],"Grid")
-        self.handlers[2]=(miniatures_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[2],"Miniatures", True)
-        self.handlers[3]=(whiteboard_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[3],"Whiteboard")
-        self.handlers[4]=(fog_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[4],"Fog")
-        self.handlers[5]=(map_handler(self.tabs,-1,self.canvas))
-        self.tabs.AddPage(self.handlers[5],"General")
-        self.tabs.SetSelection(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_tabs.SetSelection(2)
         self.sizer = wx.BoxSizer(wx.VERTICAL)
         self.sizer.Add(self.canvas, 1, wx.EXPAND)
-        self.sizer.Add(self.tabs, 0, wx.EXPAND)
+        self.sizer.Add(self.layer_tabs, 0, wx.EXPAND)
         self.SetSizer(self.sizer)
         self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.on_layer_change)
         #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
         self.load_default()
 
-        ## Components for making Map Based plugins that create new tabs.
-        component.add('map_tabs', self.tabs)
-        component.add('map_layers', self.handlers)
-        component.add('map_wnd', self)
-
     def OnLeave(self, evt):
         if "__WXGTK__" in wx.PlatformInfo: wx.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
 
@@ -789,41 +787,41 @@
         os.chdir(self.root_dir)
 
     def get_current_layer_handler(self):
-        return self.handlers[self.current_layer]
+        return self.layer_handlers[self.current_layer]
 
     def get_tab_index(self, layer):
         """Return the index of a chatpanel in the wxNotebook."""
-        for i in xrange(self.tabs.GetPageCount()):
-            if (self.tabs.GetPageText(i) == layer):
+        for i in xrange(self.layer_tabs.GetPageCount()):
+            if (self.layer_tabs.GetPageText(i) == layer):
                 return i
         return 0
 
     def on_layer_change(self, evt):
-        layer = self.tabs.GetPage(evt.GetSelection())
-        for i in xrange(0, len(self.handlers)):
-            if layer == self.handlers[i]: self.current_layer = i
+        layer = self.layer_tabs.GetPage(evt.GetSelection())
+        for i in xrange(0, len(self.layer_handlers)):
+            if layer == self.layer_handlers[i]: self.current_layer = i
         if self.current_layer == 0:
-            bg = self.handlers[0]
+            bg = self.layer_handlers[0]
             if (self.session.my_role() != self.session.ROLE_GM): bg.url_path.Show(False)
             else: bg.url_path.Show(True)
         self.canvas.Refresh(False)
         evt.Skip()
 
     def on_left_down(self, evt):
-        self.handlers[self.current_layer].on_left_down(evt)
+        self.layer_handlers[self.current_layer].on_left_down(evt)
 
     #double click handler added by Snowdog 5/03
     def on_left_dclick(self, evt):
-        self.handlers[self.current_layer].on_left_dclick(evt)
+        self.layer_handlers[self.current_layer].on_left_dclick(evt)
 
     def on_right_down(self, evt):
-        self.handlers[self.current_layer].on_right_down(evt)
+        self.layer_handlers[self.current_layer].on_right_down(evt)
 
     def on_left_up(self, evt):
-        self.handlers[self.current_layer].on_left_up(evt)
+        self.layer_handlers[self.current_layer].on_left_up(evt)
 
     def on_motion(self, evt):
-        self.handlers[self.current_layer].on_motion(evt)
+        self.layer_handlers[self.current_layer].on_motion(evt)
 
     def MapBar(self, id, data):
         self.canvas.MAP_MODE = data
@@ -840,8 +838,8 @@
         except: pass
 
     def update_tools(self):
-        for h in self.handlers:
-            self.handlers[h].update_info()
+        for h in self.layer_handlers:
+            h.update_info()
 
     def on_hk_map_layer(self, evt):
         id = self.top_frame.mainmenu.GetHelpString(evt.GetId())
@@ -851,7 +849,7 @@
         elif id == "Whiteboard Layer": self.current_layer = self.get_tab_index("Whiteboard")
         elif id == "Fog Layer": self.current_layer = self.get_tab_index("Fog")
         elif id == "General Properties": self.current_layer = self.get_tab_index("General")
-        self.tabs.SetSelection(self.current_layer)
+        self.layer_tabs.SetSelection(self.current_layer)
 
     def on_flush_cache(self, evt):
         ImageHandler.flushCache()
--- a/orpg/mapper/map_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/map_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -34,11 +34,6 @@
 from miniatures_msg import *
 from whiteboard_msg import *
 from fog_msg import *
-import traceback
-from orpg.dirpath import dir_struct
-
-from xml.etree.ElementTree import ElementTree, Element, iselement
-from xml.etree.ElementTree import fromstring, tostring, parse
 
 """
 <map name=? id=? >
@@ -51,37 +46,25 @@
 
 """
 
-def Crash(type, value, crash):
-    crash_report = open(dir_struct["home"] + 'crash-report.txt', "w")
-    traceback.print_exception(type, value, crash, file=crash_report)
-    crash_report.close()
-    msg = ''
-    crash_report = open(dir_struct["home"] + 'crash-report.txt', "r")
-    for line in crash_report: msg += line
-    print msg
-    crash_report.close()
-
 class map_msg(map_element_msg_base):
 
     def __init__(self,reentrant_lock_object = None):
-        print 'class map_msg'
         self.tagname = "map"
-        map_element_msg_base.__init__(self, reentrant_lock_object)
+        map_element_msg_base.__init__(self,reentrant_lock_object)
 
-    def init_from_dom(self, xml_dom):
-        print 'init_from_dom', self.tagname
+    def init_from_dom(self,xml_dom):
         self.p_lock.acquire()
-        if xml_dom.tag == self.tagname:
+        if xml_dom.tagName == 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.get("action") == "new":
+            if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new":
                 self.clear()
             # Process all of the properties in each tag
-            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 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 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)
@@ -101,19 +84,18 @@
         self.p_lock.release()
 
     def set_from_dom(self,xml_dom):
-        print 'set_from_dom'
         self.p_lock.acquire()
-        if xml_dom.tag == self.tagname:
+        if xml_dom.tagName == 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.get("action") == "new":
+            if self.tagname == "map" and xml_dom.hasAttribute("action") and xml_dom.getAttribute("action") == "new":
                 self.clear()
             # Process all of the properties in each tag
-            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 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 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)
@@ -137,4 +119,3 @@
 
     def get_changed_xml(self, action="update", output_action=1):
         return map_element_msg_base.get_changed_xml(self, action, output_action)
-crash = sys.excepthook = Crash
--- a/orpg/mapper/miniatures.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/miniatures.py	Mon Nov 23 03:36:26 2009 -0600
@@ -99,7 +99,6 @@
         self.bottom = bmp.GetHeight()
         self.isUpdated = False
         self.gray = False
-        print bmp
         self.set_bmp(bmp)
 
     def __del__(self):
@@ -320,41 +319,47 @@
             dc.DrawText(label,x+1,y+1)
 
     def toxml(self, action="update"):
-        mini = Element('miniature')
-        if action == 'del':
-            mini.set('action', action)
-            mini.set('id', str(self.id))
-            return tostring(mini)
-        mini.set('action', action)
-        mini.set('id', str(self.id))
-        mini.set('label', self.label)
+        if action == "del":
+            xml_str = "<miniature action='del' id='" + self.id + "'/>"
+            return xml_str
+        xml_str = "<miniature"
+        xml_str += " action='" + action + "'"
+        xml_str += " label='" + self.label + "'"
+        xml_str+= " id='" + self.id + "'"
         if self.pos != None:
-            mini.set('posx', str(self.pos.x))
-            mini.set('posy', str(self.pos.y))
-        if self.heading != None: mini.set('heading', str(self.heading))
-        if self.face != None: mini.set('face', str(self.face))
-        if self.path != None: mini.set('path', str(urllib.quote(self.path).replace('%3A', ':')))
-        mini.set('locked', '1') if self.locked else mini.set('locked', '0')
-        mini.set('hide', '1') if self.hide else mini.set('hide', '0')
-        if self.snap_to_align != None: mini.set('align', str(self.snap_to_align))
-        if self.id != None: mini.set('zorder', str(self.zorder))
-        if self.width != None: mini.set('width', str(self.width))
-        if self.height != None: mini.set('height', str(self.height))
+            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.face != None: xml_str += " face='" + str(self.face) + "'"
+        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:
-            mini.set('local', str(self.local))
-            mini.set('localPath', str(urllib.quote(self.localPath).replace('%3A', ':')))
-            mini.set('localTime', str(localTime))
+            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 mini
+            print 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("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.set_bmp(ImageHandler.load(self.path, 'miniature', self.id))
@@ -391,7 +396,9 @@
         # 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,
+        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):
@@ -485,14 +492,16 @@
 
     def layerToXML(self, action="update"):
         """ format  """
-        mini_string = ""
+        minis_string = ""
         if self.miniatures:
-            for m in self.miniatures: mini_string = m.toxml(action)
-        if mini_string != '':
-            s = Element('miniatures')
-            s.set('serial', str(self.serial_number))
-            s.append(mini_string)
-            return tostring(s)
+            for m in self.miniatures: minis_string += m.toxml(action)
+        if minis_string != '':
+            s = "<miniatures"
+            s += " serial='" + str(self.serial_number) + "'"
+            s += ">"
+            s += minis_string
+            s += "</miniatures>"
+            return s
         else: return ""
 
     def layerTakeDOM(self, xml_dom):
@@ -521,9 +530,9 @@
                 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'))
-                image = ImageHandler.load(path, 'miniature', id)
-                mini = BmpMiniature(id, path, image, pos, heading, face, label, locked, hide, snap_to_align, zorder, width, height, func='minis')
-                self.miniatures.append(mini)
+                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'))
                     local = True
@@ -550,13 +559,13 @@
         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 not modify:
                     start = path.rfind("/") + 1
-                    if self.canvas.parent.layer_handlers[2].auto_label: min_label = path[start:len(path)-4]
+                    if self.canvas.parent.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_miniature(id, path, pos=pos, label=min_label, local=True, 
@@ -567,7 +576,7 @@
                     self.miniatures[len(self.miniatures)-1].localTime = time.time()
                     self.miniatures[len(self.miniatures)-1].path = path
             else:
-                print xml_dom.getAttribute('msg')
+                print xml_dom.get('msg')
         except Exception, e:
             print e
             print recvdata
--- a/orpg/mapper/miniatures_handler.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/miniatures_handler.py	Mon Nov 23 03:36:26 2009 -0600
@@ -420,7 +420,6 @@
             oldz = self.sel_rmin.zorder
             # Make sure the mini isn't sticky front or back
             if (oldz != MIN_STICKY_BACK) and (oldz != MIN_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
@@ -434,7 +433,6 @@
             #     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
@@ -452,10 +450,8 @@
 
             # Make sure the mini isn't sticky front or back
             if (oldz != MIN_STICKY_BACK) and (oldz != MIN_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['miniatures'].miniatures)
-	    ##  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
@@ -471,18 +467,15 @@
             oldz = self.sel_rmin.zorder
             # Make sure the mini isn't sticky front or back
             if (oldz != MIN_STICKY_BACK) and (oldz != MIN_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['miniatures'].collapse_zorder()
 
         elif id == MIN_FRONTBACK_UNLOCK:
-            #print "Unlocked/ unstickified..."
             if self.sel_rmin.zorder == MIN_STICKY_BACK: self.sel_rmin.zorder = MIN_STICKY_BACK + 1
             elif self.sel_rmin.zorder == MIN_STICKY_FRONT: self.sel_rmin.zorder = MIN_STICKY_FRONT - 1
         elif id == MIN_LOCK_BACK: self.sel_rmin.zorder = MIN_STICKY_BACK
@@ -497,7 +490,6 @@
     def on_miniature(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()):
-            print session.my_role()
             self.infoPost("You must be either a player or GM to use the miniature Layer")
             return
         min_url = self.min_url.GetValue()
@@ -505,8 +497,6 @@
         if min_url == "" or min_url == "http://": return
         if min_url[:7] != "http://" : min_url = "http://" + min_url
         # make label
-        if self.auto_label: print 'auto-label'
-        if not self.auto_label: print 'False'
         if self.auto_label and min_url[-4:-3] == '.':
             start = min_url.rfind("/") + 1
             min_label = min_url[start:len(min_url)-4]
@@ -517,7 +507,6 @@
         try:
             id = 'mini-' + self.canvas.frame.session.get_next_id()
             # make the new mini appear in top left of current viewable map
-            print id
             dc = wx.ClientDC(self.canvas)
             self.canvas.PrepareDC(dc)
             dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
@@ -527,7 +516,6 @@
         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()
@@ -771,9 +759,7 @@
 
     def role_is_gm_or_player(self):
         session = self.canvas.frame.session
-        print session.my_role(), session.ROLE_GM
         if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER) and (session.use_roles()):
-            print 'role is gm or player'
             self.infoPost("You must be either a player or GM to use the miniature Layer")
             return False
         return True
--- a/orpg/mapper/miniatures_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/miniatures_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -79,12 +79,12 @@
 
     def init_from_dom(self,xml_dom):
         self.p_lock.acquire()
-        if xml_dom.tag == self.tagname:
-            if xml_dom.keys():
-                for k in xml_dom.keys():
-                    self.init_prop(k, xml_dom.get(k))
+        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.getchildren():
+            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
@@ -107,12 +107,12 @@
 
     def set_from_dom(self,xml_dom):
         self.p_lock.acquire()
-        if xml_dom.tag == self.tagname:
-            if xml_dom.keys():
-                for k in xml_dom.keys():
-                    self.set_prop(k,xml_dom.get(k))
+        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.getchildren():
+            for c in xml_dom._get_childNodes():
                 mini = mini_msg(self.p_lock)
 
                 try: mini.set_from_dom(c)
--- a/orpg/mapper/whiteboard.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/whiteboard.py	Mon Nov 23 03:36:26 2009 -0600
@@ -287,7 +287,7 @@
         self.serial_number -= 1
 
     def add_line(self, line_string="", upperleft=cmpPoint(0,0), lowerright=cmpPoint(0,0), color="#000000", width=1):
-        id = 'line-' + str(self.next_serial())
+        id = 'line ' + str(self.next_serial())
         line = WhiteboardLine(id, line_string, upperleft, lowerright, color=self.color, width=self.width)
         self.lines.append(line)
         xml_str = "<map><whiteboard>"
@@ -387,7 +387,7 @@
         self.font = font
 
     def add_text(self, text_string, pos, style, pointsize, weight, color="#000000"):
-        id = 'text-' + str(self.next_serial())
+        id = 'text ' + str(self.next_serial())
         text = WhiteboardText(id,text_string, pos, style, pointsize, weight, color)
         self.texts.append(text)
         xml_str = "<map><whiteboard>"
@@ -444,6 +444,7 @@
             nodename = l._get_nodeName()
             action = l.getAttribute("action")
             id = l.getAttribute('id')
+            if self.serial_number < int(id[5:]): self.serial_number = int(id[5:])
             if action == "del":
                 if nodename == 'line':
                     line = self.get_line_by_id(id)
--- a/orpg/mapper/whiteboard_msg.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/mapper/whiteboard_msg.py	Mon Nov 23 03:36:26 2009 -0600
@@ -29,7 +29,6 @@
 __version__ = "$Id: whiteboard_msg.py,v 1.12 2007/03/09 14:11:56 digitalxero Exp $"
 
 from base_msg import *
-from xml.etree.ElementTree import ElementTree
 
 class item_msg(map_element_msg_base):
 
@@ -81,12 +80,12 @@
 
     def init_from_dom(self,xml_dom):
         self.p_lock.acquire()
-        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)
+        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())
                 try: item.init_from_dom(c)
                 except Exception, e:
                     print e
@@ -107,12 +106,12 @@
 
     def set_from_dom(self,xml_dom):
         self.p_lock.acquire()
-        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)
+        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())
                 try: item.set_from_dom(c)
                 except Exception, e:
                     print e
--- a/orpg/networking/gsclient.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/networking/gsclient.py	Mon Nov 23 03:36:26 2009 -0600
@@ -30,7 +30,6 @@
 __version__ = "$Id: gsclient.py,v 1.53 2007/10/25 21:49:34 digitalxero Exp $"
 
 import meta_server_lib
-#import orpg.tools.orpg_settings
 import orpg.tools.rgbhex
 import traceback
 
@@ -259,6 +258,7 @@
                 address = server.get('address')
                 self.cur_server_index = 999
                 self.name = server.get('name')
+                self.texts["address"].SetValue(address)
                 if self.session.is_connected():
                     if self.session.host_server == address : return
                     else: self.frame.kill_mplay_session()
--- a/orpg/networking/mplay_client.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/networking/mplay_client.py	Mon Nov 23 03:36:26 2009 -0600
@@ -122,7 +122,8 @@
         self.ROLE_PLAYER = "Player"
         self.ROLE_LURKER = "Lurker"
         ## --TaS
-        self.ip = socket.gethostbyname(socket.gethostname())
+        try: self.ip = socket.gethostbyname(socket.gethostname())
+	except: self.ip = socket.gethostbyname('localhost')
         self.remote_ip = None
         self.version = VERSION
         self.protocol_version = PROTOCOL_VERSION
@@ -733,7 +734,7 @@
     def on_group(self, id, msg, etreeEl):
         act = etreeEl.get("action")
         group_data = (id, etreeEl.get("name"), etreeEl.get("pwd"), etreeEl.get("players"))
-        if act == ('new' or 'update'):
+        if act == 'new' or act == 'update':
             self.groups[id] = group_data
             if act == 'update': self.on_group_event(mplay_event(GROUP_UPDATE, group_data))
             elif act == 'new': self.on_group_event(mplay_event(GROUP_NEW, group_data))
--- a/orpg/networking/mplay_server.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/networking/mplay_server.py	Mon Nov 23 03:36:26 2009 -0600
@@ -92,15 +92,10 @@
         self.persistant = persist
         self.mapFile = None
         ### Needs to use Element Tree closer
-        if mapFile != None:
-            f = open( mapFile )
-            tree = f.read()
-            f.close()
-        else:
-            f = open(orpg.dirpath.dir_struct["template"] + "default_map.xml")
-            tree = f.read()
-            f.close()
-        self.game_map.init_from_xml(fromstring(tree))
+        if mapFile != None: tree = parse(mapFile)
+        else: tree = parse(dir_struct["template"] + "default_map.xml")
+        tree = tree.getroot()
+        self.game_map.init_from_xml(tostring(tree))
 
     def save_map(self):
         if self.mapFile is not None and self.persistant == 1 and self.mapFile.find("default_map.xml") == -1:
@@ -191,7 +186,7 @@
             #el.set('to', player)
             #el.set('from', '0')
             #el.set('group_id', group)
-            #el.text(msg)
+            #el.append(msg)
             self.outbox.put("<msg to='" + player + "' from='0' group_id='" + group + "' />" + msg)
 
     def change_group(self, group_id, groups):
@@ -319,7 +314,6 @@
         # try to use it.
         try:
             self.banDom = parse(self.userPath + 'ban_list.xml')
-            #self.banDom.normalize()
             self.banDoc = self.banDom.getroot()
 
             for element in self.banDom.findall('banned'):
@@ -362,7 +356,6 @@
         # try to use it.
         try:
             self.configDom = parse(self.userPath + 'server_ini.xml')
-            #self.configDom.normalize()
             self.configDoc = self.configDom.getroot()
             if hasattr(self, 'bootPassword'): self.boot_pwd = self.bootPassword
             else:
@@ -476,8 +469,6 @@
             #pull information from config file DOM
             try:
                 roomdefaults = self.configDom.findall("room_defaults")[0]
-                #rd.normalize()
-                #roomdefaults = self.rd.documentElement
                 try:
                     setting = roomdefaults.findall('passwords')[0]
                     rpw = setting.get('allow')
@@ -488,10 +479,10 @@
                 except: self.log_msg("Room Defaults: [Warning] Allowing Passworded Rooms")
                 try:
                     setting = roomdefaults.findall('map')[0]
-                    map = setting.get('file')
-                    if map != "":
-                        roomdefault_map = self.userPath + map.replace("myfiles/", "")
-                        self.log_msg("Room Defaults: Using " + str(map) + " for room map")
+                    mapper = setting.get('file')
+                    if mapper != "":
+                        roomdefault_map = self.userPath + mapper.replace("myfiles/", "")
+                        self.log_msg("Room Defaults: Using " + str(mapper) + " for room map")
                 except: self.log_msg("Room Defaults: [Warning] Using Default Map")
 
                 try:
@@ -758,13 +749,11 @@
             data = ServerPlugins.preParseOutgoing()
             for msg in data:
                 try:
-                    #xml_dom = parseXml(msg)
                     xml_dom = fromstring(msg).getroot()
                     if xml_dom.get('from') and int(xml_dom.get('from')) > -1:
                         xml_dom.set('from', '-1')
                     xml_dom.set('to', 'all')
                     self.incoming_msg_handler(xml_dom, msg)
-                    #xml_dom.unlink()
                 except: pass
             self.p_lock.release()
             time.sleep(0.250)
@@ -1113,15 +1102,9 @@
         new_stub.EnableMessageLogging = self.log_network_messages
         self.sendMsg(newsock, new_stub.toxml("new"), False, None)
 
-        #  try to remove circular refs
-        #if xml_dom:
-        #    xml_dom.unlink()
-
         # send confirmation
         data = self.recvMsg(newsock, new_stub.useCompression, new_stub.compressionType)
-        try:
-            xml_dom = XML(data)
-            #xml_dom = xml_dom._get_documentElement()
+        try: xml_dom = XML(data)
         except Exception, e:
             print e
             (remote_host,remote_port) = newsock.getpeername()
@@ -1129,7 +1112,8 @@
             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)
+            self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='" + props['id'] + "' group_id='0' />" + bad_xml_string, 
+                            new_stub.useCompression, new_stub.compressionType)
 
             time.sleep(2)
             newsock.close()
@@ -1165,7 +1149,6 @@
             time.sleep(1)
             self.log_msg("Connection terminating due to version incompatibility with client (ver: " + props['version'] + "  protocol: " + props['protocol_version'] + ")" )
             newsock.close()
-            #if xml_dom: xml_dom.unlink()
             return None
 
         ip = props['ip']
@@ -1178,7 +1161,6 @@
             #  Give messages time to flow
             time.sleep(1)
             newsock.close()
-            #if xml_dom: xml_dom.unlink()
             return None
 
         """
@@ -1235,7 +1217,6 @@
 
         #  Display the lobby message
         self.SendLobbyMessage(newsock,props['id'])
-        #if xml_dom: xml_dom.unlink()
 
     def checkClientVersion(self, clientversion):
         minv = self.minClientVersion.split('.')
@@ -1353,7 +1334,6 @@
         #  Parse the XML received from the connecting client"""
         try:
             xml_dom = XML(data)
-            #xml_dom = xml_dom._get_documentElement()
 
         except:
             try: newsock.close()
@@ -1380,14 +1360,6 @@
             traceback.print_exc()
             return #returning causes connection thread instance to terminate
 
-        #  Again attempt to clean out DOM stuff
-        """
-        try: if xml_dom: xml_dom.unlink()
-        except:
-            print "The following exception caught unlinking xml_dom:"
-            traceback.print_exc()
-            return #returning causes connection thread instance to terminate"""
-
     """
     #========================================================
     #
@@ -1420,20 +1392,15 @@
                 data = None
             except Exception, e:
                 self.log_msg(str(e))
-                #if xml_dom: xml_dom.unlink()
-        #if xml_dom: xml_dom.unlink()
         self.log_msg("message handler thread exiting...")
         self.incoming_event.set()
 
     def parse_incoming_dom(self, data):
-        #debug((data, tostring(data) if iselement(data) else 'None element'))  Sometimes I catch an error.
         end = data.find(">") #locate end of first element of message
         head = data[:end+1]
-        #self.log_msg(head)
         xml_dom = None
         try:
             xml_dom = XML(head)
-            #xml_dom = xml_dom._get_documentElement()
             self.message_action(xml_dom, data)
 
         except Exception, e:
@@ -1488,7 +1455,6 @@
         if act == "set":
             role = xml_dom.get("role")
             boot_pwd = xml_dom.get("boot_pwd")
-        #xml_dom.unlink()
         if group_id != "0":
             self.handle_role(act, player, role, boot_pwd, group_id)
             self.log_msg(("role", (player, role)))
@@ -1505,7 +1471,6 @@
             msg ="<msg to='" + player + "' from='" + player + "' group_id='" + group_id + "'>"
             msg += "<font color='#FF0000'>PONG!?!</font>"
         self.players[player].outbox.put(msg)
-        #xml_dom.unlink()
 
     def do_system(self, xml_dom, data):
         pass
@@ -1825,7 +1790,6 @@
     def incoming_player_handler(self, xml_dom, data):
         id = xml_dom.get("id")
         act = xml_dom.get("action")
-        #group_id = xml_dom.get("group_id")
         group_id = self.players[id].group_id
         ip = self.players[id].ip
         self.log_msg("Player with IP: " + str(ip) + " joined.")
@@ -1981,7 +1945,6 @@
             given_boot_pwd = None
             try:
                 xml_dom = XML(msg)
-                #xml_dom = xml_dom._get_documentElement()
                 given_boot_pwd = xml_dom.get("boot_pwd")
 
             except:
@@ -2092,7 +2055,7 @@
 
     def admin_banip(self, ip, name="", silent = 0):
         "Ban a player from a server from the console"
-        self.adming_buile_banlist() ### Alpha ###
+        self.admin_build_banlist() ### Alpha ###
         try:
             self.ban_list[ip] = {}
             self.ban_list[ip]['ip'] = ip
@@ -2412,8 +2375,7 @@
                         self.players[pid].outbox.put(msg)
                     except: pass
             elif cmd == "savemaps":
-                for g in self.groups.itervalues():
-                    g.save_map()
+                for g in self.groups.itervalues(): g.save_map()
                 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Persistent room maps saved"
                 self.players[pid].outbox.put(msg)
             else:
--- a/orpg/networking/mplay_server_gui.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/networking/mplay_server_gui.py	Mon Nov 23 03:36:26 2009 -0600
@@ -568,7 +568,7 @@
     def OnCreateGroup( self, data ):
         (room, room_id, player, pwd) = data
         self.groups.AddGroup(data)
-        self.conns.roomList[room_id] = name
+        self.conns.roomList[room_id] = room
         data = (room, room_id, player)
         self.conns.updateRoom(data)
 
--- a/orpg/orpg_version.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/orpg_version.py	Mon Nov 23 03:36:26 2009 -0600
@@ -4,7 +4,7 @@
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
 DISTRO = "Traipse Beta"
 DIS_VER = "Ornery Orc"
-BUILD = "091010-00"
+BUILD = "091123-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/plugindb.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/plugindb.py	Mon Nov 23 03:36:26 2009 -0600
@@ -55,7 +55,7 @@
 
     def FetchList(self, parent):
         retlist = []
-        for litem in parent.findall('lobject'):
+        for litem in parent.find('list').findall('lobject'):
             if litem.get('type') == 'int': retlist.append(int(litem.text))
             if litem.get('type') == 'bool': retlist.append(litem.text == 'True')
             elif litem.get('type') == 'float': retlist.append(float(litem.text))
@@ -67,7 +67,6 @@
     def GetList(self, plugname, listname, defaultval=list(), verbose=False):
         listname = self.safe(listname)
         plugin = self.etree.find(plugname)
-
         if plugin is None or plugin.find(listname) is None:
             msg = ["plugindb: no value has been stored for", listname, "in",
                    plugname, "so the default has been returned"]
--- a/orpg/templates/feature.xml	Tue Nov 10 14:11:28 2009 -0600
+++ b/orpg/templates/feature.xml	Mon Nov 23 03:36:26 2009 -0600
@@ -1,108 +1,164 @@
+<nodehandler class="tabber_handler" icon="help" module="containers" name="Traipse OpenRPG" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,139,110" icon="note" map="Traipse OpenRPG" 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 gametree 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.
 
-<nodehandler class="tabber_handler" icon="help" module="containers" name="OpenRPG+ 1.7.1" version="1.0">
-  <nodehandler class="link_handler" icon="html" module="forms" name="Release Notes" version="1.0">
-    <link href="http://openrpg.digitalxero.net/wiki/index.php?page=Release+Notes"/>
-  </nodehandler>
-  <nodehandler class="link_handler" icon="html" module="forms" name="OpenRPG User Guide" version="1.0">
-    <link href="http://openrpg.digitalxero.net"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="help" module="core" name="Load Die Roller Notes" version="1.0">
-    <file name="die_roller_notes.xml"/>
+There are two ways of references node data. A Root Reference and a Child Reference.
+
+A Root Reference uses this syntax:
+!@Node::Child::Data@!
+
+Root References find the data within the node first by looking at the nodes in the tree.  The location of the node must be exact or you will return an Invalid Reference!
+
+A Child Reference uses this syntax:
+!!Node::Child::Data!!
+
+Child References work from within a container.  Child References obtain the map from a child node and then look for the node data using an appended Root Reference.  As long as the Child Reference node remains in in the same location relative to the reference, you can move the nodes around and never need to change your references again.
+
+Child Referencing works from within a PC Sheet node as well.
+
+Syntax for Special PC Sheet Nodes:
+The nodes for the specialized PC Sheets now have a new syntax.
+
+Abilities:
+To reference an Ability, use the name or abbreviation of the Ability.
+Example: !@Mikael::Strength@!
+
+This will return the Ability, the Ability Score, and it's Modifier.
+
+Mod Referencing:
+If you want to find the Ability Modifier only, use Ability::Mod
+Example: !@Mikael::Strength::Mod@!
+
+Ability Checks:
+Ability Checks are simplified as well.  Simply add Check to the reference.
+Example: !@Mikael::Strength::Check@!
+
+The new referencing features are useful if you want to refence the ability modifier in other nodes.
+
+Skills:
+Skills work the similar to Abilities.  To refence a skill's ranks use the Skill syntax
+Example: !@Jonethan::Skill::Jump@!
+
+This will return the ranks you have in Jump.  Skill Checks are made by appending Check to the statement.
+Example: !@Jonethan::Skill::Jump::Check@!
+
+If you want to reference the skills modifier, use the Mod syntax
+Example: !@Jonethan::Skill::Jump::Mod@!
+
+Combat:
+You can now reference your attacks easily with the gametree.  Using the Attack syntax you can select modifier type, and a weapon to attack with.
+Example: !@Kammen-Pai::Attack::M::Dagger@!
+
+Modifier Type:
+There are two modifier types Melee (M) or Ranged(R) You will see I added can use the long word or the short hand.
+
+Spells:
+If the PC Sheet you are using has Spells and Powers, you can use the Cast syntax to cast a spell or use a power.
+Example: !@Kammen-Pai::Cast::Ray of Frost@!
+
+The data returned is the description of the spells actions.  Spell actions are difficult to remember, and even harder to code, so this will at least work as an emoteable reference and a reminder of how the spell works.
+
+Feats:
+Feats will work the same way as spells.  Because Feats and Spells have rulings that require such finesse it is not very easy to code them.  However you will receive an easy to use reference point for what your Feat does.
+Using the Feat syntax you can the description of the Feat.
+Example: !@Kammen-Pai::Feat::Ability Focus@!
+
+</text></nodehandler><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG" module="forms" name="Release Notes" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse" />
   </nodehandler>
-  <nodehandler class="group_handler" icon="gear" module="containers" name="Templates" status="useful" version="1.0">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="group_handler" icon="flask" module="containers" name="Nodes" status="useful" version="1.0">
-      <group_atts border="1" cols="1"/>
-      <nodehandler class="file_loader" icon="note" module="core" name="Create New Text Box" version="1.0">
-        <file name="textctrl.xml"/>
+  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG" module="forms" name="Traipse User Guide" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
+  </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">
+    <group_atts border="1" cols="1" />
+    <nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
+      <group_atts border="1" cols="1" />
+      <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" module="core" name="Create New List Box" version="1.0">
-        <file name="listbox.xml"/>
+      <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" module="core" name="Create New Grid" version="1.0">
-        <file name="grid.xml"/>
+      <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" module="core" name="Create New Web Link" version="1.0">
-        <file name="link.xml"/>
+      <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" module="core" name="Create New Web Image" version="1.0">
-        <file name="image.xml"/>
+      <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 class="group_handler" module="containers" name="Containers" status="useful" version="1.0">
-      <group_atts border="1" cols="1"/>
-      <nodehandler class="file_loader" module="core" name="Create New Folder" version="1.0">
-        <file name="group.xml"/>
+    <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Templates" module="containers" name="Containers" status="useful" version="1.0">
+      <group_atts border="1" cols="1" />
+      <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" module="core" name="Create New Tabber" version="1.0">
-        <file name="tabber.xml"/>
+      <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" module="core" name="Create New Splitter" version="1.0">
-        <file name="split.xml"/>
+      <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" module="core" name="Create New Form" version="1.0">
-        <file name="form.xml"/>
+      <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 class="group_handler" icon="gear" module="containers" name="Tools" status="useful" version="1.0">
-      <group_atts border="1" cols="1"/>
-      <nodehandler class="file_loader" icon="gear" module="core" name="Create New Chat Macro" version="1.0">
-        <file name="macro.xml"/>
+    <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
+      <group_atts border="1" cols="1" />
+      <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" module="core" name="Create New Miniature Library Tool" version="1.0">
-        <file name="minlib.xml"/>
+      <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" module="core" name="Create remote node loader" version="1.0">
-        <file name="urloader.xml"/>
+      <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 class="file_loader" icon="d20" module="core" name="Create New d20 Character Tool" version="1.0">
-        <file name="d20character.xml"/>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New d20 Character Tool" version="1.0">
+        <file name="d20character.xml" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="d20" module="core" name="Create New St*r W*rs Character Tool" version="1.0">
-        <file name="StarWars_d20character.xml"/>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" 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" module="core" name="3rd Edition Character Tool" version="1.0">
-        <file name="dnd3e.xml"/>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="3rd Edition Character Tool" version="1.0">
+        <file name="dnd3e.xml" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="d20" module="core" name="3.5 Tool" version="1.0">
-        <file name="dnd3.5.xml"/>
+      <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::Tools" module="core" name="3.5 Tool" version="1.0">
+        <file name="dnd3.5.xml" />
       </nodehandler>
     </nodehandler>
   </nodehandler>
-  <nodehandler class="group_handler" icon="browser" module="containers" name="OpenRPG+ Resources" version="1.0">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="link_handler" icon="html" module="forms" name="OpenRPG+ Home Page" version="1.0">
-      <link href="http://openrpg.digitalxero.net"/>
+  <nodehandler border="1" class="group_handler" cols="1" icon="browser" map="Traipse OpenRPG" module="containers" name="OpenRPG+ Resources" version="1.0">
+    <group_atts border="1" cols="1" />
+    <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" module="forms" name="OpenRPG Project Page" version="1.0">
-      <link href="http://openrpg.digitalxero.net"/>
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" module="forms" name="OpenRPG Forums" version="1.0">
-      <link href="http://forums.rpghost.com/forumdisplay.php?s=&amp;forumid=118"/>
+    <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" module="forms" name="Submit A Bug Report" version="1.0">
-      <link href="http://openrpg.digitalxero.net/phpbb/viewtopic.php?t=10"/>
+    <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" module="forms" name="OpenRPG Plugin HQ" version="1.0">
-      <link href="http://openrpg.mduo13.com/plugins.php"/>
+    <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" module="forms" name="OpenRPG Web Ring" version="1.0">
-      <link href="http://www.ringsurf.com/netring?ring=OpenRPG;action=home"/>
+    <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" module="forms" name="AutoRealm" version="1.0">
-      <link href="http://www.gryc.ws/autorealm.htm"/>
-    </nodehandler>
-    <nodehandler class="link_handler" icon="html" module="forms" name="PCGen" version="1.0">
-      <link href="http://pcgen.sourceforge.net/01_overview.php"/>
+    <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 class="group_handler" module="containers" name="Examples (Adventures)" version="1.0">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="file_loader" icon="d20" module="core" name="Bastion Press d20 Adventure" version="1.0">
-      <file name="Bastion_adventure.xml"/>
+  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG" module="containers" name="Examples (Adventures)" version="1.0">
+    <group_atts border="1" cols="1" />
+    <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" module="core" name="Darwin's World d20 Adventure" version="1.0">
-      <file name="Darwin_adventure.xml"/>
+    <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>
--- a/upmana/manifest.py	Tue Nov 10 14:11:28 2009 -0600
+++ b/upmana/manifest.py	Mon Nov 23 03:36:26 2009 -0600
@@ -65,7 +65,7 @@
 
     def FetchList(self, parent):
         retlist = []
-        for litem in parent.findall('lobject'):
+        for litem in parent.find('list').findall('lobject'):
             if litem.get('type') == 'int': retlist.append(int(litem.text))
             if litem.get('type') == 'bool': retlist.append(litem.text == 'True')
             elif litem.get('type') == 'float': retlist.append(float(litem.text))