changeset 195:b633f4c64aae alpha

Traipse Alpha 'OpenRPG' {100219-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Patch-2) New Features: New Namespace method with two new syntaxes Fixes: Fix to Server GUI startup errors Fix to Server GUI Rooms tab updating Fix to Chat and Settings if non existant die roller is picked Fix to Dieroller and .open() used with .vs(). Successes are correctly calculated Fix to Alias Lib's Export to Tree, Open, Save features Fix to alias node, now works properly Fix to Splitter node, minor GUI cleanup
author sirebral
date Sat, 24 Apr 2010 08:37:20 -0500
parents 4b2884f29a72
children 0bc44a57ae6c
files data/tips.txt orpg/chat/chat_msg.py orpg/chat/chatwnd.py orpg/chat/commands.py orpg/dieroller/base.py orpg/dieroller/rollers/7sea.py orpg/dieroller/rollers/__init__.py orpg/dieroller/rollers/alternity.py orpg/dieroller/rollers/d20.py orpg/dieroller/rollers/gurps.py orpg/dieroller/rollers/hackmaster.py orpg/dieroller/rollers/hero.py orpg/dieroller/rollers/mythos.py orpg/dieroller/rollers/runequest.py orpg/dieroller/rollers/savage.py orpg/dieroller/rollers/std.py orpg/dieroller/rollers/trinity.py orpg/dieroller/rollers/wfrpg.py orpg/dieroller/rollers/wod.py orpg/dieroller/rollers/wodex.py orpg/dieroller/utils.py orpg/gametree/nodehandlers/StarWarsd20.py orpg/gametree/nodehandlers/chatmacro.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/core.py orpg/gametree/nodehandlers/d20.py orpg/gametree/nodehandlers/dnd3e.py orpg/gametree/nodehandlers/forms.py orpg/gametree/nodehandlers/map_miniature_nodehandler.py orpg/gametree/nodehandlers/minilib.py orpg/gametree/nodehandlers/rpg_grid.py orpg/gametree/nodehandlers/voxchat.py orpg/main.py orpg/mapper/background.py orpg/mapper/background_handler.py orpg/mapper/background_msg.py orpg/mapper/base.py orpg/mapper/base_handler.py orpg/mapper/base_msg.py orpg/mapper/fog_msg.py orpg/mapper/grid.py orpg/mapper/grid_handler.py orpg/mapper/grid_msg.py orpg/mapper/images.py orpg/mapper/map.py orpg/mapper/map_handler.py orpg/mapper/map_msg.py orpg/mapper/map_prop_dialog.py orpg/mapper/min_dialogs.py orpg/mapper/miniatures.py orpg/mapper/miniatures_handler.py orpg/mapper/miniatures_msg.py orpg/mapper/region.py orpg/mapper/whiteboard.py orpg/mapper/whiteboard_handler.py orpg/mapper/whiteboard_msg.py orpg/networking/gsclient.py orpg/networking/meta_server_lib.py orpg/networking/mplay_client.py orpg/networking/mplay_messaging.py orpg/networking/mplay_server.py orpg/networking/mplay_server_gui.py orpg/orpg_version.py orpg/orpg_windows.py orpg/orpg_xml.py orpg/player_list.py orpg/templates/default_LobbyMessage.html orpg/templates/default_Lobby_map.xml orpg/templates/default_ignorelist.txt orpg/templates/default_settings.xml orpg/templates/feature.xml orpg/templates/metaservers.cache orpg/templates/nodes/4e_char_sheet.xml orpg/templates/nodes/Idiots_guide_to_openrpg.xml orpg/templates/nodes/Traipse_User_Guide.xml orpg/templates/nodes/Userguide098.xml orpg/templates/nodes/Userguide13.xml orpg/templates/nodes/die_macro.xml orpg/templates/nodes/file_loader.xml orpg/templates/nodes/split.xml orpg/templates/nodes/textctrl.xml orpg/templates/nodes/u_idiots_guide_to_openrpg.xml orpg/templates/nodes/wizards.xml orpg/tools/InterParse.py orpg/tools/aliaslib.py orpg/tools/inputValidator.py orpg/tools/orpg_log.py orpg/tools/orpg_settings.py orpg/tools/passtool.py orpg/tools/predTextCtrl.py orpg/tools/pubsub.py orpg/tools/rgbhex.py orpg/tools/scriptkit.py orpg/tools/server_probe.py orpg/tools/toolBars.py orpg/tools/validate.py plugins/bcg/__init__.py plugins/bcg/tok_dialogs.py plugins/bcg/token_handler.py plugins/bcg/tokens.py plugins/bcg/tokens_msg.py plugins/xxbcg.py plugins/xxblank.py plugins/xxchatnotify.py plugins/xxgsc.py plugins/xxhiddendice.py plugins/xxminiquicknote.py plugins/xxmouse-zoom.py plugins/xxspell.py plugins/xxurl2link.py readme.txt start_noupdate.py upmana/updatemana.py upmana/validate.py
diffstat 112 files changed, 1852 insertions(+), 6005 deletions(-) [+]
line wrap: on
line diff
--- a/data/tips.txt	Fri Jan 15 22:45:51 2010 -0600
+++ b/data/tips.txt	Sat Apr 24 08:37:20 2010 -0500
@@ -18,7 +18,7 @@
 
 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.
+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 Traipse using 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. 
 
@@ -30,6 +30,8 @@
 
 You can customise OpenRPG's behaviour in four ways: plugins, custom die rollers, game system specific nodes and by using filters.
 
+The Traipse EZ Tree is a quick way to create node references.
+
 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
--- a/orpg/chat/chat_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/chat_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,13 +21,13 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: chat_msg.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $
+#   $Id: chat_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Contains class definitions for manipulating <chat/> messages
 #
 #
 
-__version__ = "$Id: chat_msg.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: chat_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpgCore import *
 from chat_version import CHAT_VERSION
@@ -48,8 +48,7 @@
         self.takexml(xml_text)
 
     def __del__(self):
-        if self.chat_dom:
-            self.chat_dom.unlink()
+        if self.chat_dom: self.chat_dom.unlink()
 
     def toxml(self):
         return tostring(self.chat_dom)
--- a/orpg/chat/chatwnd.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/chatwnd.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
@@ -37,7 +37,7 @@
 #   + Added simple_html_repair() to post() to fix malformed html in the chat window
 #
 
-__version__ = "$Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $"
+__version__ = "$Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
@@ -45,11 +45,10 @@
 ##
 import os, time, re, sys, traceback, webbrowser, commands, chat_msg, chat_util
 
-from orpg.orpg_version import VERSION
+from orpg.orpg_version import VERSION, DISTRO, DIS_VER, BUILD
 from orpg.orpg_windows import *
 from orpg.player_list import WG_LIST
 from orpg.dirpath import dir_struct
-#from orpg.tools.metamenus import MenuEx #Needed?
 from string import *
 
 import cStringIO # for reading inline imagedata as a stream
@@ -62,11 +61,11 @@
 from orpg.tools.orpg_settings import settings
 import orpg.tools.predTextCtrl
 from orpg.tools.orpg_log import logger, debug
+from orpg.tools.InterParse import Parse
 from orpg.orpgCore import component
 from xml.etree.ElementTree import tostring
 
-from orpg.networking.mplay_client import MPLAY_CONNECTED  # needed to only send typing/not_typing messages while connected
-
+from orpg.networking.mplay_client import MPLAY_CONNECTED  
 NEWCHAT = False
 try:
     import wx.webview
@@ -83,10 +82,10 @@
         self.accum = ""
         self.special_tags = ['hr', 'br', 'img']
     
-    def handle_data(self, data):  # quote cdata literally
+    def handle_data(self, data):  
         self.accum += data
     
-    def handle_entityref(self, name): # entities must be preserved exactly
+    def handle_entityref(self, name): 
         self.accum += "&" + name + ";"
     
     def handle_starttag(self, tag, attrs):
@@ -95,11 +94,10 @@
             for attrib in attrs: self.accum += ' ' + attrib[0] + '="' + attrib[1] + '"'
             self.accum += '>'
     
-    def handle_charref(self, name):  # charrefs too
+    def handle_charref(self, name):
         self.accum += "&#" + name + ";"
 htmlstripper = HTMLStripper()
 
-# utility function;  see Post().
 
 def strip_html(string):
     "Return string tripped of html tags."
@@ -114,7 +112,6 @@
     filename = settings.get_setting('GameLogPrefix')
     if filename > '' and filename[0] != commands.ANTI_LOG_CHAR:
         filename = filename + time.strftime( '-%Y-%m-%d.html', time.localtime( time.time() ) )
-        #filename = time.strftime( filename, time.localtime( time.time() ) )
         timestamp = time.ctime(time.time())
         header = '[%s] : ' % ( timestamp );
         if settings.get_setting('TimeStampGameLog') != '1': header = ''
@@ -122,8 +119,9 @@
             f = open( dir_struct["user"] + filename, 'a' )
             f.write( '<div class="'+c+'">%s%s</div>\n' % ( header, text ) )
             f.close()
-        except:
+        except Exception, e:
             print "could not open " + dir_struct["user"] + filename + ", ignoring..."
+            print 'Error given', e
             pass
 
 # This class displayes the chat information in html?
@@ -136,12 +134,7 @@
 #
 class chat_html_window(wx.html.HtmlWindow):
     """ a wxHTMLwindow that will load links  """
-    # initialization subroutine
-    #
-    # !self : instance of self
-    # !parent :
-    # !id :
-    
+
     def __init__(self, parent, id):
         wx.html.HtmlWindow.__init__(self, parent, id, 
                                     style=wx.SUNKEN_BORDER|wx.html.HW_SCROLLBAR_AUTO|wx.NO_FULL_REPAINT_ON_RESIZE)
@@ -150,18 +143,14 @@
         self.Bind(wx.EVT_LEFT_UP, self.LeftUp)
         self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
         if "gtk2" in wx.PlatformInfo: self.SetStandardFonts()
-        # def __init__ - end
 
-    
     def onPopup(self, evt):
         self.PopupMenu(self.menu)
 
-    
     def LeftUp(self, event):
         event.Skip()
         wx.CallAfter(self.parent.set_chat_text_focus, None)
 
-    
     def build_menu(self):
         self.menu = wx.Menu()
         item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy")
@@ -174,13 +163,11 @@
         wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText()))
         wx.TheClipboard.Close()
 
-    
     def scroll_down(self):
         maxrange = self.GetScrollRange(wx.VERTICAL)
         pagesize = self.GetScrollPageSize(wx.VERTICAL)
         self.Scroll(-1, maxrange-pagesize)
 
-    
     def mouse_wheel(self, event):
         amt = event.GetWheelRotation()
         units = amt/(-(event.GetWheelDelta()))
@@ -197,19 +184,12 @@
     
     def GetPageSource(self):
         return self.GetParser().GetSource()
-
-    # This subroutine fires up the webbrowser when a link is clicked.
-    #
-    # !self : instance of self
-    # !linkinfo : instance of a class that contains the link information
     
     def OnLinkClicked(self, linkinfo):
         href = linkinfo.GetHref()
         wb = webbrowser.get()
         wb.open(href)
-    # def OnLinkClicked - end
 
-    
     def CalculateAllFonts(self, defaultsize):
         return [int(defaultsize * 0.4),
                 int(defaultsize * 0.7),
@@ -219,7 +199,6 @@
                 int(defaultsize * 2),
                 int(defaultsize * 2.5)]
 
-    
     def SetDefaultFontAndSize(self, fontname, fontsize):
         """Set 'fontname' to the default chat font.
            Returns current font settings in a (fontname, fontsize) tuple."""
@@ -239,7 +218,6 @@
             self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
             self.Bind(wx.webview.EVT_WEBVIEW_BEFORE_LOAD, self.OnLinkClicked)
 
-        #Wrapers so I dont have to add special Code
         def SetPage(self, htmlstring):
             self.SetPageSource(htmlstring)
 
@@ -366,7 +344,6 @@
 
     def get_tab_index(self, chatpanel):
         "Return the index of a chatpanel in the wxNotebook."
-
         for i in xrange(self.GetPageCount()):
             if (self.GetPage(i) == chatpanel):
                 return i
@@ -450,7 +427,6 @@
         selected_idx = event.GetSelection()
         self.SetPageImage(selected_idx, 1)
         page = self.GetPage(selected_idx)
-        #wx.CallAfter(page.set_chat_text_focus, 0)
         event.Skip()
 
 """
@@ -505,10 +481,6 @@
         # who receives outbound messages, either "all" or "playerid" string
         self.sendtarget = sendtarget
         self.type = tab_type
-        #self.sound_player = component.get('sound') #Removing!
-        # create die roller manager
-        #self.DiceManager = component.get('DiceManager') #Removing!
-        # create rpghex tool
         self.r_h = orpg.tools.rgbhex.RGBHex()
         self.h = 0
         self.set_colors()
@@ -536,7 +508,7 @@
         self.lastSend = 0         #  this is used to help implement the player typing indicator
         self.lastPress = 0        #  this is used to help implement the player typing indicator
         self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) #require to keep text at bottom of chat when text entry expands --SD
+        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) 
         self.build_ctrls()
         StartupFont = self.settings.get_setting("defaultfont")
         StartupFontSize = self.settings.get_setting("defaultfontsize")
@@ -778,7 +750,6 @@
         self.build_menu()
         entries = []
         entries.append((wx.ACCEL_CTRL, ord('H'), self.setChatFocusMenu.GetId()))
-        #entries.append((wx.ACCEL_CTRL, wx.WXK_TAB, SWAP_TABS))
         return entries
 
     
@@ -788,18 +759,15 @@
     def back_tabs(self, evt):
         self.parent.AdvanceSelection(False)
 
-    # This subroutine builds the controls for the chat frame
-    #
-    # !self : instance of self
-    
     def build_ctrls(self):
         self.chatwnd = chat_html_window(self,-1)
         self.set_colors()
         wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header())
+        welcome = "<b>Welcome to <a href='http://www.knowledgearcana.com//content/view/199/128/'>"
+        welcome += DISTRO +'</a> '+ DIS_VER +' {'+BUILD+'},'
+        welcome += ' built on OpenRPG '+ VERSION +'</b>'
         if (self.sendtarget == "all"):
-            wx.CallAfter(self.Post, self.colorize(self.syscolor, 
-                "<b>Welcome to <a href='http://www.openrpg.com'>OpenRPG</a> version " + self.version + "...  </b>"))
-            #self.chat_cmds.on_help()
+            wx.CallAfter(self.Post, self.colorize(self.syscolor, welcome))
         self.chattxt = orpg.tools.predTextCtrl.predTextCtrl(self, -1, "", 
                         style=wx.TE_PROCESS_ENTER |wx.TE_PROCESS_TAB|wx.TE_LINEWRAP, 
                         keyHook = self.myKeyHook, validator=None )
@@ -838,7 +806,6 @@
         self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar)
         self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down)
         self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy)
-    # def build_ctrls - end
 
     def build_bar(self):
         self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -855,11 +822,9 @@
             self.build_formating()
             self.build_colorbutton()
 
-    
     def build_scroll(self):
         self.scroll_lock = wx.Button( self, wx.ID_ANY, "Scroll ON",size= wx.Size(80,25))
 
-    
     def build_alias(self):
         self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
         self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName])
@@ -949,8 +914,6 @@
         else: self.toolbar_sizer.Show(self.formatSizer, True)
         self.toolbar_sizer.Layout()
 
-    # Heroman - Ideally, we would use static labels...
-    
     def build_colorbutton(self):
         self.color_button = createMaskedButton(self, dir_struct["icon"]+'textcolor.gif', 
                                                     'Text Color', wx.ID_ANY, '#bdbdbd', 
@@ -983,13 +946,6 @@
         else: logger.general("Error, self.chatwnd.GetInternalRepresentation() return None")
         evt.Skip()
 
-    #  This subroutine is registered with predTextCtrl to be run for every OnChar event
-    #  It checks if we need to send a typing message
-
-    #
-    #  self:  duh
-    #  event:  raw KeyEvent from OnChar()
-    
     def myKeyHook(self, event):
         if self.session.get_status() == MPLAY_CONNECTED:   #  only do if we're connected
             thisPress = time.time()                #  thisPress is local temp variable
@@ -1005,11 +961,6 @@
             logger.debug("Exit chat_panel->myKeyHook(self, event) return 0")
             return 0
 
-    #  This subroutine gets called once a second by the typing Timer
-    #  It checks if we need to send a not_typing message
-    #
-    #  self:  duh
-    
     def typingTimerFunc(self, event):
         #following added by mDuo13
         ##############refresh_counter()##############
@@ -1027,12 +978,7 @@
                                                    #  If we're not already typing, then self.lastSend will be 0
 
                 self.sendTyping(0)                 #  send a typing event here (0 for False)
-    #  This subroutine actually takes care of sending the messages for typing/not_typing events
-    #
-    #  self:  duh
-    #  typing:  boolean
 
-    
     def sendTyping(self, typing):
         if typing:
             self.lastSend = time.time()  #  remember our send time for use in myKeyHook()
@@ -1047,11 +993,6 @@
             if status_text == "" or status_text == None: status_text = "Idle"
             self.session.set_text_status(status_text)
 
-    # This subroutine sets the colors of the chat based on the settings in the
-    # self instance.
-    #
-    # !self : instance of self
-    
     def set_colors(self):
         # chat window backround color
         self.bgcolor = self.settings.get_setting('bgcolor')
@@ -1067,18 +1008,11 @@
         self.emotecolor = self.settings.get_setting('emotecolor')
         # color of whispers
         self.whispercolor = self.settings.get_setting('whispercolor')
-    # def set_colors - end
-
-    # This subroutine will insert text into the chat window
-    #
-    # !self : instance of self
-    # !txt : text to be inserted into the chat window
     
     def set_chat_text(self, txt):
         self.chattxt.SetValue(txt)
         self.chattxt.SetFocus()
         self.chattxt.SetInsertionPointEnd()
-    # def set_chat_text - end
 
     
     def get_chat_text(self):
@@ -1088,22 +1022,11 @@
     
     def set_chat_text_focus(self, event):
         wx.CallAfter(self.chattxt.SetFocus)
-    # def set_chat_text_focus - end
-
-    # This subrtouine grabs the user input and make the special keys and
-    # modifiers work.
-    #
-    # !self : instance of self
-    # !event :
-    #
-    # Note:  self.chattxt now handles it's own Key events.  It does, however still
-    #        call it's parent's (self) OnChar to handle "default" behavior.
 
     def submit_chat_text(self, s):
         self.histidx = -1
         self.temptext = ""
         self.history = [s] + self.history 
-        #if not len(macroText): self.chattxt.SetValue("")
 
         # play sound
         sound_file = self.settings.get_setting("SendSound")
@@ -1144,17 +1067,12 @@
         elif event.GetKeyCode() == wx.WXK_UP:
             logger.debug("event.GetKeyCode() == wx.WXK_UP")
             if self.histidx < len(self.history)-1:
-                #text that's not in history but also hasn't been sent to chat gets stored in self.temptext
-                #this way if someone presses the up key, they don't lose their current message permanently
-                #(unless they also press enter at the time)
                 if self.histidx is -1: self.temptext = self.chattxt.GetValue()
                 self.histidx += 1
                 self.chattxt.SetValue(self.history[self.histidx])
                 self.chattxt.SetInsertionPointEnd()
             else:
-                self.histidx = len(self.history) -1#in case it got too high somehow, this should fix it
-                #self.InfoPost("**Going up? I don't think so.**")
-            #print self.histidx, "in",self.history
+                self.histidx = len(self.history) -1
 
         ## DOWN KEY
         elif event.GetKeyCode() == wx.WXK_DOWN:
@@ -1166,9 +1084,7 @@
                     self.chattxt.SetValue(self.temptext)
                 else: self.chattxt.SetValue(self.history[self.histidx])
                 self.chattxt.SetInsertionPointEnd()
-            else: self.histidx = -1 #just in case it somehow got below -1, this should fix it
-                #self.InfoPost("**Going down? I don't think so.**")
-            #print self.histidx, "in",self.history
+            else: self.histidx = -1 
 
         ## TAB KEY
         elif  event.GetKeyCode() == wx.WXK_TAB:
@@ -1242,8 +1158,6 @@
         ## NOTHING
         else: event.Skip()
         logger.debug("Exit chat_panel->OnChar(self, event)")
-    # def OnChar - end
-
     
     def onDieRoll(self, evt):
         """Roll the dice based on the button pressed and the die modifiers entered, if any."""
@@ -1260,12 +1174,6 @@
         self.ParsePost(dieText, 1, 1)
         self.chattxt.SetFocus()
 
-    # This subroutine saves a chat buffer as html to a file chosen via a
-    # FileDialog.
-    #
-    # !self : instance of self
-    # !evt :
-    
     def on_chat_save(self, evt):
         f = wx.FileDialog(self,"Save Chat Buffer",".","","HTM* (*.htm*)|*.htm*|HTML (*.html)|*.html|HTM (*.htm)|*.htm",wx.SAVE)
         if f.ShowModal() == wx.ID_OK:
@@ -1274,9 +1182,7 @@
             file.close()
         f.Destroy()
         os.chdir(dir_struct["home"])
-    # def on_chat_save - end
 
-    
     def ResetPage(self):
         self.set_colors()
         buffertext = self.chatwnd.Header() + "\n"
@@ -1286,9 +1192,6 @@
                                                                             "<br />\n").replace("\n\n", '')
         return buffertext
 
-    # This subroutine sets the color of selected text, or base text color if
-    # nothing is selected
-    
     def on_text_color(self, event):
         hexcolor = self.r_h.do_hex_color_dlg(self)
         if hexcolor != None:
@@ -1305,25 +1208,11 @@
                 self.settings.set_setting('mytextcolor',hexcolor)
                 self.set_colors()
                 self.Post()
-    # def on_text_color - end
 
-    # This subroutine take a color and a text string and formats it into html.
-    #
-    # !self : instance of self
-    # !color : color for the text to be set
-    # !text : text string to be included in the html.
-    
     def colorize(self, color, text):
         """Puts font tags of 'color' around 'text' value, and returns the string"""
         return "<font color='" + color + "'>" + text + "</font>"
-    # def colorize - end
 
-    # This subroutine takes and event and inserts text with the basic format
-    # tags included.
-    #
-    # !self : instance of self
-    # !event :
-    
     def on_text_format(self, event):
         id = event.GetId()
         txt = self.chattxt.GetValue()
@@ -1338,9 +1227,7 @@
         self.chattxt.SetValue(txt)
         self.chattxt.SetInsertionPointEnd()
         self.chattxt.SetFocus()
-    # def on_text_format - end
 
-    
     def lock_scroll(self, event):
         if self.lockscroll:
             self.lockscroll = False
@@ -1353,28 +1240,16 @@
             self.lockscroll = True
             self.scroll_lock.SetLabel("Scroll OFF")
 
-    # This subroutine will popup a text window with the chatbuffer contents
-    #
-    # !self : instance of self
-    # !event :
-    
     def pop_textpop(self, event):
         """searchable popup text view of chatbuffer"""
         h_buffertext = self.ResetPage()
         h_dlg = orpgScrolledMessageFrameEditor(self, h_buffertext, "Text View of Chat Window", None, (500,300))
         h_dlg.Show(True)
 
-    # This subroutine will change the dimension of the window
-    #
-    # !self : instance of self
-    # !event :
-    
     def OnSize(self, event=None):
         event.Skip()
         wx.CallAfter(self.scroll_down)
-    # def OnSize - end
 
-    
     def scroll_down(self):
         self.Freeze()
         self.chatwnd.scroll_down()
@@ -1386,17 +1261,14 @@
         self.set_colors()
         self.chatwnd.SetPage(self.chatwnd.Header())
 
-    
     def system_message(self, text):
         self.send_chat_message(text,chat_msg.SYSTEM_MESSAGE)
         self.SystemPost(text)
 
-    
     def info_message(self, text):
         self.send_chat_message(text,chat_msg.INFO_MESSAGE)
         self.InfoPost(text)
 
-    
     def get_gms(self):
         the_gms = []
         for playerid in self.session.players:
@@ -1404,7 +1276,6 @@
                 if self.session.players[playerid][7]=="GM" and self.session.group_id != '0': the_gms += [playerid]
         return the_gms
 
-    
     def GetName(self):
         self.AliasLib = component.get('alias')
         player = self.session.get_my_info()
@@ -1415,7 +1286,6 @@
                 return [self.chat_display_name([self.AliasLib.alias[0], player[1], player[2]]), self.AliasLib.alias[1]]
         return [self.chat_display_name(player), "Default"]
 
-    
     def GetFilteredText(self, text):
         advregex = re.compile('\"(.*?)\"', re.I)
         self.AliasLib = component.get('alias')
@@ -1430,11 +1300,9 @@
                         text = text.replace(match, newmatch)
         return text
 
-    
     def emote_message(self, text):
-        text = self.NormalizeParse(text)
+        text = Parse.Normalize(text)
         text = self.colorize(self.emotecolor, text)
-
         if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE)
         elif self.type == MAIN_TAB and self.sendtarget == "gm":
             msg_type = chat_msg.WHISPER_EMOTE_MESSAGE
@@ -1449,13 +1317,10 @@
         text = "** " + name + " " + text + " **"
         self.EmotePost(text)
 
-    
     def whisper_to_players(self, text, player_ids):
         tabbed_whispers_p = self.settings.get_setting("tabbedwhispers")
-        # Heroman - apply any filtering selected
-        text = self.NormalizeParse(text)
+        text = Parse.Normalize(text)
         player_names = ""
-        # post to our chat before we colorize
         for m in player_ids:
             id = m.strip()
             if self.session.is_valid_id(id):
@@ -1469,7 +1334,6 @@
         comma.join(player_ids)
         if (self.sendtarget == "all"):
             self.InfoPost("<i>whispering to "+ player_names + " " + text + "</i> ")
-        # colorize and loop, sending whisper messages to all valid clients
         text = self.colorize(self.mytextcolor, text)
         for id in player_ids:
             id = id.strip()
@@ -1501,11 +1365,7 @@
         if send: self.session.send(msg.toxml(),player_id)
         del msg
 
-    #### incoming chat message handler #####
-    
     def post_incoming_msg(self, msg, player):
-
-        # pull data
         type = msg.get_type()
         text = msg.get_text()
         alias = msg.get_alias()
@@ -1522,12 +1382,8 @@
                 if str(e) != "'module' object has no attribute 'receive_msg'":
                     logger.general(traceback.format_exc())
                     logger.general("EXCEPTION: " + str(e))
-        #end mDuo13 added code
-        #image stripping for players' names
         strip_img = self.settings.get_setting("Show_Images_In_Chat")
         if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name)
-        #end image stripping. --mDuo13, July 11th, 2005
-        # default sound
         recvSound = "RecvSound"
         # act on the type of messsage
         if (type == chat_msg.CHAT_MESSAGE):
@@ -1624,17 +1480,15 @@
         sound_file = self.settings.get_setting(recvSound)
         if sound_file != '':
             component.get('sound').play(sound_file)
+
     #### Posting helpers #####
 
-    
     def InfoPost(self, s):
         self.Post(self.colorize(self.infocolor, s), c='info')
 
-    
     def SystemPost(self, s):
         self.Post(self.colorize(self.syscolor, s), c='system')
 
-    
     def EmotePost(self, s):
         self.Post(self.colorize(self.emotecolor, s), c='emote')
 
@@ -1675,15 +1529,9 @@
         if aliasInfo[1] != 'Default':
             self.settings.set_setting("mytextcolor", defaultcolor)
             self.set_colors()
-        #following line based on sourceforge patch #880403 from mDuo
-        # EDIT: Had to rework blank line check to handle malformed HTML throwing error.
-        #       this limits the effectiveness of this check -SD
         lineHasText = 1
         try: lineHasText = strip_html(s).replace("&nbsp;","").replace(" ","").strip()!=""
         except:
-            # HTML parser has errored out (most likely). Being as all we are doing is
-            # scanning for empty/blank lines anyway there is no harm in letting a
-            # troublesome message though. Worst case is a blank line to chat.
             lineHasText = 1
         if lineHasText:
             #following added by mDuo13
@@ -1731,12 +1579,6 @@
             else: self.InfoPost("Failed to send message, unknown send type for this tab")
         self.parsed=0
 
-    #
-    # TimeIndexString()
-    #
-    # time indexing for chat display only (don't log time indexing)
-    # added by Snowdog 4/04
-    
     def TimeIndexString(self):
         try:
             mtime = ""
@@ -1749,86 +1591,10 @@
             logger.general("EXCEPTION: " + str(e))
             return "[ERROR]"
 
-    ####  Post with parsing dice ####
-    
     def ParsePost(self, s, send=False, myself=False):
-        s = self.NormalizeParse(s)
+        s = Parse.Normalize(s)
         self.set_colors()
         self.Post(s,send,myself)
-    
-    def NormalizeParse(self, s):
-        for plugin_fname in self.activeplugins.keys():
-            plugin = self.activeplugins[plugin_fname]
-            try: s = plugin.pre_parse(s)
-            except Exception, e:
-                if str(e) != "'module' object has no attribute 'post_msg'":
-                    logger.general(traceback.format_exc())
-                    logger.general("EXCEPTION: " + str(e))
-        if self.parsed == 0:
-            s = self.ParseNode(s)
-            s = self.ParseDice(s)
-            s = self.ParseFilter(s)
-            self.parsed = 1
-        return s
-    
-    def ParseFilter(self, s):
-        s = self.GetFilteredText(s)
-        return s
-    
-    def ParseNode(self, s):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        #[a-zA-Z0-9 _\-\.]
-        reg = re.compile("(!@(.*?)@!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            newstr = self.ParseNode(self.resolve_nodes(matches[i][1]))
-            s = s.replace(matches[i][0], newstr, 1)
-        return s
-    
-    def ParseDice(self, s):
-        """Parses player input for embedded dice rolls"""
-        reg = re.compile("\[([^]]*?)\]")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            newstr = self.PraseUnknowns(matches[i])
-            qmode = 0
-            newstr1 = newstr
-            if newstr[0].lower() == 'q':
-                newstr = newstr[1:]
-                qmode = 1
-            if newstr[0].lower() == '#':
-                newstr = newstr[1:]
-                qmode = 2
-            try: newstr = component.get('DiceManager').proccessRoll(newstr)
-            except: pass
-            if qmode == 1:
-                s = s.replace("[" + matches[i] + "]", 
-                            "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
-            elif qmode == 2:
-                s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
-            else: s = s.replace("[" + matches[i] + "]", 
-                            "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
-        return s
-    
-    def PraseUnknowns(self, s):
-	# Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY
-        newstr = "0"
-        reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            lb = "Replace '?' with: "
-            if len(matches[i][0]):
-                lb = matches[i][1] + "?: "
-            dlg = wx.TextEntryDialog(self, lb, "Missing Value?")
-            dlg.SetValue('')
-            if matches[i][0] != '':
-                dlg.SetTitle("Enter Value for " + matches[i][1])
-            if dlg.ShowModal() == wx.ID_OK: newstr = dlg.GetValue()
-            if newstr == '': newstr = '0'
-            s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1)
-            dlg.Destroy()
-        return s
 
     # This subroutine builds a chat display name.
     #
@@ -1854,8 +1620,8 @@
         else:
             dlg.Destroy()
             return None
+
     # def get_color - end
-
     def replace_quotes(self, s):
         in_tag = 0
         i = 0
@@ -1869,179 +1635,3 @@
             i += 1
         return rs
 
-    def resolve_loop(self, node, path, step, depth):
-        if step == depth:
-            return self.resolution(node)
-        else:
-            child_list = node.findall('nodehandler')
-            for child in child_list:
-                if step == depth: break
-                if child.get('name') == path[step]:
-                    node = child
-                    step += 1
-                    if node.get('class') in ('dnd35char_handler', 
-                                            "SWd20char_handler", 
-                                            "d20char_handler", 
-                                            "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth)
-                    elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth)
-                    else: self.resolve_loop(node, path, step, depth)
-
-    def resolve_grid(self, node, path, step, depth):
-        if step == depth:
-            self.data = 'Invalid Grid Reference!'
-            return
-        cell = tuple(path[step].strip('(').strip(')').split(','))
-        grid = node.find('grid')
-        rows = grid.findall('row')
-        col = rows[int(self.ParseDice(cell[0]))-1].findall('cell')
-        try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data'
-        except: self.data = 'Invalid Grid Reference!'
-        return
-
-    def resolution(self, node):
-        if self.passed == False:
-            self.passed = True
-            if node.get('class') == 'textctrl_handler': 
-                s = str(node.find('text').text)
-            else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
-        else:
-            s = ''
-        s = self.ParseMap(s, node)
-        s = self.ParseParent(s, node.get('map'))
-        self.data = s
-
-    def ParseMap(self, s, node):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!!(.*?)!!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            tree_map = node.get('map')
-            tree_map = tree_map + '::' + matches[i][1]
-            newstr = '!@'+ tree_map +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            s = self.ParseNode(s)
-            s = self.ParseParent(s, tree_map)
-        return s
-
-    def ParseParent(self, s, tree_map):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!#(.*?)#!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            ## Build the new tree_map
-            new_map = tree_map.split('::')
-            del new_map[len(new_map)-1]
-            parent_map = matches[i][1].split('::')
-            ## Find an index or use 1 for ease of use.
-            try: index = new_map.index(parent_map[0])
-            except: index = 1
-            ## Just replace the old tree_map from the index.
-            new_map[index:len(new_map)] = parent_map
-            newstr = '::'.join(new_map)
-            newstr = '!@'+ newstr +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            #s = self.ParseMap(s, node) ## Needs to be added
-            s = self.ParseNode(s)
-        return s
-
-    def resolve_nodes(self, s):
-        self.passed = False
-        self.data = 'Invalid Reference!'
-        value = ""
-        path = s.split('::')
-        depth = len(path)
-        self.gametree = component.get('tree')
-        try: node = self.gametree.tree_map[path[0]]['node']
-        except Exception, e: return self.data
-        if node.get('class') in ('dnd35char_handler', 
-                                "SWd20char_handler", 
-                                "d20char_handler", 
-                                "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
-        elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
-        else: self.resolve_loop(node, path, 1, depth)
-        return self.data
-
-    def resolve_cust_loop(self, node, path, step, depth):
-        node_class = node.get('class')
-        ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
-        if step == depth: self.resolution(node)
-        ##Build Abilities dictionary##
-        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities')
-        else: ab = node.find('abilities')
-        ab_list = ab.findall('stat'); pc_stats = {}
-
-        for ability in ab_list:
-            pc_stats[ability.get('name')] = ( 
-                    str(ability.get('base')), 
-                    str((int(ability.get('base'))-10)/2) )
-            pc_stats[ability.get('abbr')] = ( 
-                    str(ability.get('base')), 
-                    str((int(ability.get('base'))-10)/2) )
-
-        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
-        else: ab = node.find('saves')
-        ab_list = ab.findall('save')
-        for save in ab_list:
-            pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
-            if save.get('name') == 'Fortitude': abbr = 'Fort'
-            if save.get('name') == 'Reflex': abbr = 'Ref'
-            if save.get('name') == 'Will': abbr = 'Will'
-            pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
-
-        if path[step].lower() == 'skill':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
-            node = node.find('skills')
-            child_list = node.findall('skill')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = child.get('rank')
-                    elif path[step+2].lower() == 'check':
-                        self.data = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']'
-            return
-
-        if path[step].lower() == 'feat':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
-            node = node.find('feats')
-            child_list = node.findall('feat')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
-            return
-        if path[step].lower() == 'cast':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snp')
-            node = node.find('spells')
-            child_list = node.findall('spell')
-            for child in child_list:
-                if path[step+1].lower() == child.get('name').lower():
-                    if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
-            return
-        if path[step].lower() == 'attack':
-            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat')
-            if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm':
-                bonus_text = '(Melee)'
-                bonus = node.find('attacks')
-                bonus = bonus.find('melee')
-                bonus = bonus.attrib; d = int(pc_stats['Str'][1])
-            elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r':
-                bonus_text = '(Ranged)'
-                bonus = node.find('attacks')
-                bonus = bonus.find('ranged')
-                bonus = bonus.attrib; d = int(pc_stats['Dex'][1])
-            for b in bonus:
-                d += int(bonus[b])
-            bonus = str(d)
-            if path[step+2] == None: self.data = bonus
-            else:
-                weapons = node.find('attacks')
-                weapons = weapons.findall('weapon')
-                for child in weapons:
-                    if path[step+2].lower() == child.get('name').lower():
-                        self.data = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']'
-            return
-        elif pc_stats.has_key(path[step].title()):
-            if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
-            elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1]
-            elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
-            return
--- a/orpg/chat/commands.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/chat/commands.py	Sat Apr 24 08:37:20 2010 -0500
@@ -7,7 +7,6 @@
 #   on_whisper(self,text)
 #
 
-
 import string, time
 import orpg.orpg_version
 import orpg.orpg_windows
@@ -26,63 +25,41 @@
 try:
     import cmd_ext
     print "Importing Developer Extended Command Set"
-except:
-    pass
+except: pass
 ##----------------------------------------------------------------
 
 ANTI_LOG_CHAR = '!'
 
 class chat_commands:
 
-    # Initialization subroutine.
-    #
-    # !self : instance of self
-    # !chat : instance of the chat window to write to
-    
     def __init__(self,chat):
         self.post = chat.Post
         self.colorize = chat.colorize
         self.session = chat.session
-        #self.send = chat.session.send
         self.settings = chat.settings
         self.chat = chat
         self.cmdlist = {}
         self.shortcmdlist = {}
         self.defaultcmds()
         self.defaultcmdalias()
-        # def __init__ - end
         self.previous_whisper = []
 
-
-        # This subroutine will take a text string and attempt to match to a series
-        # of implemented emotions.
-        #
-        # !self : instance of self
-        # !text : string of text matching an implemented emotion
-    
     def addcommand(self, cmd, function, helpmsg):
         if not self.cmdlist.has_key(cmd) and not self.shortcmdlist.has_key(cmd):
             self.cmdlist[cmd] = {}
             self.cmdlist[cmd]['function'] = function
             self.cmdlist[cmd]['help'] = helpmsg
-            #print 'Command Added: ' + cmd
 
-    
     def addshortcmd(self, shortcmd, longcmd):
         if not self.shortcmdlist.has_key(shortcmd) and not self.cmdlist.has_key(shortcmd):
             self.shortcmdlist[shortcmd] = longcmd
 
-    
     def removecmd(self, cmd):
         if self.cmdlist.has_key(cmd):
             del self.cmdlist[cmd]
         elif self.shortcmdlist.has_key(cmd):
             del self.shortcmdlist[cmd]
 
-        #print 'Command Removed: ' + cmd
-
-
-    
     def defaultcmds(self):
         self.addcommand('/help', self.on_help, '- Displays this help message')
         self.addcommand('/version', self.on_version, ' - Displays current version of OpenRPG.')
@@ -112,7 +89,6 @@
         self.addcommand('/purge', self.on_purge, 'This will clear the entire chat window')
         self.addcommand('/advfilter', self.on_filter, 'This will toggle the Advanced Filter')
 
-    
     def defaultcmdalias(self):
         self.addshortcmd('/?', '/help')
         self.addshortcmd('/he', '/me')
@@ -123,18 +99,14 @@
         self.addshortcmd('/date', '/time')
         self.addshortcmd('/desc', '/description')
         self.addshortcmd('/d', '/description')
-
-        #This is just an example or a differant way the shorcmd can be used
         self.addshortcmd('/sleep', '/me falls asleep')
 
-    
     def docmd(self,text):
         cmdsearch = string.split(text,None,1)
         cmd = string.lower(cmdsearch[0])
         start = len(cmd)
         end = len(text)
         cmdargs = text[start+1:end]
-
         if self.cmdlist.has_key(cmd):
             self.cmdlist[cmd]['function'](cmdargs)
         elif self.shortcmdlist.has_key(cmd):
@@ -143,37 +115,26 @@
             msg = "Sorry I don't know what %s is!" % (cmd)
             self.chat.InfoPost(msg)
 
-    
     def on_filter(self, cmdargs):
-        #print self.chat.advancedFilter
         test = not self.chat.advancedFilter
-        #print test
-
         for tab in self.chat.parent.whisper_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         for tab in self.chat.parent.null_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         for tab in self.chat.parent.group_tabs:
             tab.advancedFilter = not self.chat.advancedFilter
-
         if self.chat.parent.GMChatPanel != None:
             self.chat.parent.GMChatPanel.advancedFilter = not self.chat.advancedFilter
-
         self.chat.advancedFilter = not self.chat.advancedFilter
-
         if self.chat.advancedFilter:
             self.chat.InfoPost("Advanced Filtering has been turned On")
         else:
             self.chat.InfoPost("Advanced Filtering has been turned Off")
 
-    
     def on_purge(self, cmdargs):
         self.chat.PurgeChat()
         self.chat.InfoPost('Chat Buffer has been Purged!')
 
-    
     def on_sound(self, cmdargs):
         if len(cmdargs) < 8:
             self.chat.InfoPost("You must provide a URL for the file name, it does not work for just local sound files")
@@ -186,9 +147,7 @@
         else:
             snd = cmdargs.replace('&', '&amp;')
             loop = ''
-
         type = 'remote'
-
         (name, ip, id, text_status, version, protocol_version, client_string, role) = self.session.get_my_info()
         group_id = self.session.group_id
         if (role != 'Lurker' and group_id != '0') or self.session.get_status() != 1:
@@ -207,11 +166,9 @@
         else:
             self.chat.InfoPost("Something dun fuckered up Frank!")
 
-    
     def on_version(self, cmdargs=""):
         self.chat.InfoPost("Version is OpenRPG " + self.chat.version)
 
-    
     def on_load(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         try:
@@ -222,14 +179,12 @@
             print e
             self.chat.InfoPost("ERROR Loading settings")
 
-    
     def on_font(self, cmdargs):
         try:
             fontsettings = self.chat.set_default_font(fontname=cmdargs, fontsize=None)
         except:
             self.chat.InfoPost("ERROR setting default font")
 
-    
     def on_fontsize(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         try:
@@ -238,7 +193,6 @@
             print e
             self.chat.InfoPost("ERROR setting default font size")
 
-    
     def on_close(self, cmdargs):
         try:
             chatpanel = self.chat
@@ -250,7 +204,6 @@
         except:
             self.chat.InfoPost("Error:  cannot close private chat tab.")
 
-    
     def on_time(self, cmdargs):
         local_time = time.localtime()
         gmt_time = time.gmtime()
@@ -258,30 +211,29 @@
         self.chat.InfoPost("<br />Local: " + time.strftime(format_string)+\
                            "<br />GMT: "+time.strftime(format_string,gmt_time))
 
-    
     def on_dieroller(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         rm = component.get('DiceManager')
+        cur_die = rm.getRoller()
         try:
             rm.setRoller(args[0])
-            self.chat.SystemPost("You have changed your die roller to the <b>\"" + args[0] + "\"</b> roller.")
-            self.settings.set_setting('dieroller',args[0])
+            self.chat.SystemPost('You have changed your die roller to the <b>"' +rm.getRoller()+ '"</b> roller.')
+            self.settings.change('dieroller', rm.getRoller())
         except Exception, e:
-            print e
-            self.chat.InfoPost("Available die rollers: " + str(rm.listRollers()))
-            self.chat.InfoPost("You are using the <b>\"" + rm.getRoller() + "\"</b> die roller.")
+            rm.setRoller(cur_die)
+            self.settings.change('dieroller', str(cur_die))
+            if args[0] != '': self.chat.SystemPost(args[0]+ ' is an invalid roller.')
+            self.chat.InfoPost('Available die rollers: ' +str(rm.listRollers()) )
+            self.chat.InfoPost('You are using the <b>"' +cur_die+ '"</b> die roller.')
 
-    
     def on_ping(self, cmdargs):
         ct = time.clock()
         msg = "<ping player='"+self.session.id+"' time='"+str(ct)+"' />"
         self.session.outbox.put(msg)
 
-    
     def on_log(self,cmdargs):
         args = string.split(cmdargs,None,-1)
         logfile = self.settings.get_setting( 'GameLogPrefix' )
-
         if len( args ) == 0:
             self.postLoggingState()
         elif args[0] == "on" and logfile != '':
@@ -309,7 +261,6 @@
         else:
             self.chat.InfoPost("Unknown logging command, use 'on' or 'off'"  )
 
-    
     def postLoggingState( self ):
         logfile = self.settings.get_setting( 'GameLogPrefix' )
         try:
@@ -319,39 +270,23 @@
         suffix = time.strftime( '-%d-%m-%y.html', time.localtime( time.time() ) )
         self.chat.InfoPost('Log filename is "%s%s", system is %s logging.' % (logfile, suffix, comment) )
 
-        # This subroutine will set the players netork status.
-        #
-        #!self : instance of self
-
-    
     def on_name(self, cmdargs):
-        #only 20 chars no more! :)
         if cmdargs == "":
             self.chat.InfoPost("**Incorrect syntax for name.")
         else:
-            #txt = txt[:50]
             self.settings.set_setting('player', cmdargs)
             self.session.set_name(str(cmdargs))
 
-    # def on_status - end
-        # This subroutine will set the players netork status.
-        #
-        # !self : instance of self
-    
     def on_status(self, cmdargs):
         if cmdargs ==  "":
             self.chat.InfoPost("Incorrect synatx for status.")
         else:
-        #only 20 chars no more! :)
             txt = cmdargs[:20]
             self.session.set_text_status(str(txt))
-    # def on_status - end
 
-    
     def on_set(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         keys = self.settings.get_setting_keys()
-        #print keys
         if len(args) == 0:
             line = "<table border='2'>"
             for m in keys:
@@ -378,11 +313,6 @@
                         self.chat.set_colors()
                         self.chat.set_buffersize()
 
-        # This subroutine will display the correct usage of the different emotions.
-        #
-        #!self : instance of self
-
-    
     def on_help(self, cmdargs=""):
         cmds = self.cmdlist.keys()
         cmds.sort()
@@ -400,11 +330,6 @@
             msg += ' %s' % (self.cmdlist[cmd]['help'])
         self.chat.InfoPost(msg)
 
-        # This subroutine will either show the list of currently ignored users
-        # !self : instance of self
-        # !text : string that is comprised of a list of users to toggle the ignore flag
-
-    
     def on_ignore(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         (ignore_list, ignore_name) = self.session.get_ignore_list()
@@ -431,7 +356,6 @@
                     self.chat.InfoPost(m + " was ignored because it is an invalid player ID")
                     traceback.print_exc()
 
-    
     def on_role(self, cmdargs):
         if cmdargs == "":
             self.session.display_roles()
@@ -453,16 +377,7 @@
                     for m in player_ids:
                         self.session.set_role(m.strip(),role,role_pwd)
             except:  traceback.print_exc()
-#        return
 
-        # This subroutine implements the whisper functionality that enables a user
-        # to whisper to another user.
-        #
-        # !self : instance of self
-        # !text : string that is comprised of a list of users and the message to
-        #whisper.
-
-    
     def on_whisper(self, cmdargs):
         delim = cmdargs.find("=")
 
@@ -476,10 +391,6 @@
         mesg = string.strip(cmdargs[delim+1:])
         self.chat.whisper_to_players(mesg,player_ids)
 
-#---------------------------------------------------------
-# [START] Digitalxero Multi Whisper Group 1/1/05
-#---------------------------------------------------------
-    
     def on_groupwhisper(self, cmdargs):
         args = string.split(cmdargs,None,-1)
         delim = cmdargs.find("=")
@@ -533,11 +444,6 @@
                 else: idList = str(n) + ", " + idList
             self.on_whisper(idList + "=" + self.settings.get_setting("gwtext") + msg)
 
-#---------------------------------------------------------
-# [END] Digitalxero Multi Whisper Group 1/1/05
-#---------------------------------------------------------
-
-    
     def on_gmwhisper(self, cmdargs):
         if cmdargs == "":
             self.chat.InfoPost("**Incorrect syntax for GM Whisper.")
@@ -551,7 +457,6 @@
                 self.on_whisper(gmstring + "=" + cmdargs)
             else: self.chat.InfoPost("**No GMs to Whisper to.")
 
-    
     def on_moderate(self, cmdargs):
         if cmdargs != "":
             pos = cmdargs.find("=")
@@ -584,11 +489,9 @@
             self.session.outbox.put(msg)
         self.session.update()
 
-    
     def on_update(self, cmdargs):
         self.chat.InfoPost("This command is no longer valid")
 
-    
     def on_description(self, cmdargs):
         if len(cmdargs) <= 0:
             self.chat.InfoPost("**No description text to display." + str(delim))
@@ -599,13 +502,10 @@
         self.chat.Post(mesg)
         self.chat.send_chat_message(mesg)
 
-    
     def invoke_tab(self, cmdargs):
-        ######START mDuo13's Tab Initiator########
         try:
             int(cmdargs)
             playerid = cmdargs.strip()
-            # Check to see if parent notebook already has a private tab for player
             for panel in self.chat.parent.whisper_tabs:
                 if (panel.sendtarget == playerid):
                     self.chat.Post("Cannot invoke tab: Tab already exists.")
@@ -622,30 +522,22 @@
             nidx = self.chat.parent.get_tab_index(displaypanel)
             self.chat.parent.newMsg(nidx)
             return
-        #######END mDuo13's Tab Initiator#########
 
-
-    
     def on_remote_admin(self, cmdargs):
         args = string.split(cmdargs,None,-1)
-        #handles remote administration commands
         try:
             pass_state = 0
             pwd = self.session.orpgFrame_callback.password_manager.GetSilentPassword("server")
             if  pwd != None:
                 pass_state = 1
             else: pwd = "<i>[NONE]</i>"
-
             if len( args ) == 0:
-                #raw command return state info
                 msg = "<br /><b>Remote Administrator Config:</b>"
                 if pass_state != 1 : msg += " Password not set. Remote admin functions disabled<br />"
                 else: msg += " Enabled. Using password '"+pwd+"'<br />"
                 self.chat.SystemPost(msg)
                 return
-
             if pass_state != 1 and args[0] != "set":
-                #no commands under this point will execute unless an admin password has been previously set
                 self.chat.SystemPost("Command ignored. No remote administrator password set!!")
                 return
             msgbase = "<admin id='"+self.session.id+"' group_id='"+self.session.group_id+"' pwd='"+pwd+"'"
@@ -690,14 +582,12 @@
                     self.session.outbox.put(msg)
 
             elif args[0] == "banip":
-                #Ban a player from the server
                 try: bname = str(args[2])
                 except: bname = 'Unknown'
                 msg = msgbase + ' cmd="banip" bip="' + str(args[1]) + '" bname="' + bname + '"/>'
                 self.session.outbox.put(msg)
 
             elif args[0] == "createroom":
-                #request creation of a (temporary) persistant room
                 if len(args) < 2:
                     self.chat.SystemPost( "You must supply a name and boot password at least. <br />/admin createroom &lt;name&gt; &lt;boot password&gt; [password]" )
                     return
@@ -709,7 +599,6 @@
                 self.session.outbox.put(msg)
 
             else: self.chat.InfoPost("Unknown administrator command"  )
-            #command_function = {'banip': self.admin.r_admin_banip, 'createroom': self.r_admin_createroom,}
         except:
             self.chat.InfoPost("An error has occured while processing a Remote Administrator command!")
             traceback.print_exc()
--- a/orpg/dieroller/base.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/base.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,18 +22,16 @@
 # Author: Andrew Bennett
 # Maintainer:
 # Version:
-#   $Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $
+#   $Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This class is used to make working with dice easier
 #
 
-__version__ = "$Id: die.py,v 1.13 2007/03/13 17:53:42 digitalxero Exp $"
-
+__version__ = "$Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp Exp $"
 
 import random
 import UserList
 import copy
-#import string
 
 class die_base(UserList.UserList):
     name = None
@@ -42,11 +40,9 @@
         if isinstance(source, (int, float, basestring)):
             s = []
             s.append(di(source))
-        else:
-            s = source
+        else: s = source
         UserList.UserList.__init__(self,s)
 
-
     def sum(self):
         s = 0
         for a in self.data:
@@ -58,28 +54,19 @@
             o = other
         elif hasattr(other,"sum"):
             o = other.sum()
-        else:
-            return None
-
+        else: return None
         result = []
         for die in self:
-            if die < o:
-                result.append(die)
+            if die < o: result.append(die)
         return self.__class__(result)
 
     def __rshift__(self,other):
-
-        if type(other) == type(3) or type(other) == type(3.0):
-            o = other
-        elif hasattr(other,"sum"):
-            o = other.sum()
-        else:
-            return None
-
+        if type(other) == type(3) or type(other) == type(3.0): o = other
+        elif hasattr(other,"sum"): o = other.sum()
+        else: return None
         result = []
         for die in self:
-            if die > o:
-                result.append(die)
+            if die > o: result.append(die)
         return self.__class__(result)
 
     def __rlshift__(self,other):
@@ -88,7 +75,6 @@
     def __rrshift__(self,other):
         return self.__lshift__(other)
 
-
     def __str__(self):
         if len(self.data) > 0:
             myStr = "[" + str(self.data[0])
@@ -96,69 +82,49 @@
                 myStr += ","
                 myStr += str(a)
             myStr += "] = (" + str(self.sum()) + ")"
-        else:
-            myStr = "[] = (0)"
+        else: myStr = "[] = (0)"
         return myStr
 
     def __lt__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() < other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() < other.sum())
-        else:
-            return UserList.UserList.__lt__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() < other.sum())
+        else: return UserList.UserList.__lt__(self,other)
 
     def __le__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() <= other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() <= other.sum())
-        else:
-            return UserList.UserList.__le__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() <= other.sum())
+        else: return UserList.UserList.__le__(self,other)
 
     def __eq__(self,other):
         if type(other) == type(3) or type(other) == type(3.0):
             return (self.sum() == other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() == other.sum())
-        else:
-            return UserList.UserList.__eq__(self,other)
+        elif hasattr(other,"sum"): return (self.sum() == other.sum())
+        else: return UserList.UserList.__eq__(self,other)
 
     def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() != other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() != other.sum())
-        else:
-            return UserList.UserList.__ne__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() != other)
+        elif hasattr(other,"sum"): return (self.sum() != other.sum())
+        else: return UserList.UserList.__ne__(self,other)
 
     def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() > other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() > other.sum())
-        else:
-            return UserList.UserList.__gt__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() > other)
+        elif hasattr(other,"sum"): return  (self.sum() > other.sum())
+        else: return UserList.UserList.__gt__(self,other)
 
     def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return (self.sum() >= other)
-        elif hasattr(other,"sum"):
-            return  (self.sum() >= other.sum())
-        else:
-            return UserList.UserList.__ge__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return (self.sum() >= other)
+        elif hasattr(other,"sum"): return  (self.sum() >= other.sum())
+        else: return UserList.UserList.__ge__(self,other)
 
     def __cmp__(self,other):
         #  this function included for backwards compatibility
         #  As of 2.1, lists implement the "rich comparison"
         #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0):
-            return cmp(self.sum(), other)
-        elif hasattr(other,"sum"):
-            return  cmp(self.sum(), other.sum())
-        else:
-            return UserList.UserList.__cmp__(self,other)
-
+        if type(other) == type(3) or type(other) == type(3.0): return cmp(self.sum(), other)
+        elif hasattr(other,"sum"): return  cmp(self.sum(), other.sum())
+        else: return UserList.UserList.__cmp__(self,other)
 
     def __rcmp__(self,other):
         return self.__cmp__(other)
@@ -166,16 +132,9 @@
     def __add__(self,other):
         mycopy = copy.deepcopy(self)
         if type(other) == type(3) or type(other) == type(3.0):
-            #if other < 0:
-            #    return self.__sub__(-other)
-            #other = [di(other,other)]
             other = [static_di(other)]
-            #return self.sum() + other
-
-        elif type(other) == type("test"):
-            return self
+        elif type(other) == type("test"): return self
         mycopy.extend(other)
-        #result = UserList.UserList.__add__(mycopy,other)
         return mycopy
 
     def __iadd__(self,other):
@@ -197,17 +156,13 @@
         mycopy = copy.deepcopy(self)
         if type(other) == type(3) or type(other) == type(3.0):
             neg_die = static_di(-other)
-            #neg_die.set_value(-other)
             other = [neg_die]
-            #return self.sum() - other
-        else:
-            other = -other
+        else: other = -other
         mycopy.extend(other)
         return mycopy
 
     def __rsub__(self,other):
         mycopy = -copy.deepcopy(self)
-        #print type(other)
         if type(other) == type(3) or type(other) == type(3.0):
             new_die = di(0)
             new_die.set_value(other)
@@ -219,89 +174,62 @@
         return self.__sub__(other)
 
     def __mul__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum() * other
-        elif hasattr(other,"sum"):
-            return other.sum() * self.sum()
-        else:
-            return UserList.UserList.__mul__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum() * other
+        elif hasattr(other,"sum"): return other.sum() * self.sum()
+        else: return UserList.UserList.__mul__(self,other)
 
     def __rmul__(self,other):
         return self.__mul__(other)
 
     def __div__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return float(self.sum()) / other
-        elif hasattr(other,"sum"):
-            return  float(self.sum()) / other.sum()
-        else:
-            return UserList.UserList.__div__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return float(self.sum()) / other
+        elif hasattr(other,"sum"): return  float(self.sum()) / other.sum()
+        else: return UserList.UserList.__div__(self,other)
 
     def __rdiv__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return other / float(self.sum())
-        elif hasattr(other,"sum"):
-            return  other.sum() / float(self.sum())
-        else:
-            return UserList.UserList.__rdiv__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return other / float(self.sum())
+        elif hasattr(other,"sum"): return  other.sum() / float(self.sum())
+        else: return UserList.UserList.__rdiv__(self,other)
 
     def __mod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum()%other
-        elif hasattr(other,"sum"):
-            return  self.sum() % other.sum()
-        else:
-            return UserList.UserList.__mod__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum()%other
+        elif hasattr(other,"sum"): return self.sum() % other.sum()
+        else: return UserList.UserList.__mod__(self,other)
 
     def __rmod__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return other % self.sum()
-        elif hasattr(other,"sum"):
-            return  other.sum() % self.sum()
-        else:
-            return UserList.UserList.__rmod__(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return other % self.sum()
+        elif hasattr(other,"sum"): return  other.sum() % self.sum()
+        else: return UserList.UserList.__rmod__(self,other)
 
     def __neg__(self):
-        for i in range(len(self.data)):
-            self.data[i] = -self.data[i]
+        for i in range(len(self.data)): self.data[i] = -self.data[i]
         return self
 
     def __pos__(self):
-        for i in range(len(self.data)):
-            self.data[i] = +self.data[i]
+        for i in range(len(self.data)): self.data[i] = +self.data[i]
         return self
 
     def __abs__(self):
-        for i in range(len(self.data)):
-            self.data[i] = abs(self.data[i])
+        for i in range(len(self.data)): self.data[i] = abs(self.data[i])
         return self
-        #return abs(self.sum())
 
     def __pow__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.sum() ** other
-        elif hasattr(other,"sum"):
-            return  self.sum() ** other.sum()
-        else:
-            return UserList.UserList.__pow__(self,other)
-
+        if type(other) == type(3) or type(other) == type(3.0): return self.sum() ** other
+        elif hasattr(other,"sum"): return self.sum() ** other.sum()
+        else: return UserList.UserList.__pow__(self,other)
 
     def __rpow__(self,other):
         #  We're overloading exponentiation of ints to create "other" number of dice
-
         if other >= 1:
             result = self.__class__(self[0].sides)
-            for t in range(other-1):
-                result+=self.__class__(self[0].sides)
-        else:
-            result = None
-
+            for t in range(other-1): result+=self.__class__(self[0].sides)
+        else: result = None
         return result
 
 ### di class to handle actual dice
 
 class di:
-    def __init__(self,sides,min=1):
+    def __init__(self, sides, min=1):
         self.sides = sides
         self.history = None
         self.value = None
@@ -309,21 +237,17 @@
         self.roll(min)
 
     def __str__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
+        if len(self.history) > 1: return str(self.history)
+        else: return str(self.value)
 
     def __neg__(self):
         self.value = -self.value
-        for i in range(len(self.history)):
-            self.history[i] = -self.history[i]
+        for i in range(len(self.history)): self.history[i] = -self.history[i]
         return self
 
     def __pos__(self):
         self.value = +self.value
-        for i in range(len(self.history)):
-            self.history[i] = +self.history[i]
+        for i in range(len(self.history)): self.history[i] = +self.history[i]
         return self
 
     def __abs__(self):
@@ -333,90 +257,59 @@
         return self
 
     def __repr__(self):
-        if len(self.history) > 1:
-            return str(self.history)
-        else:
-            return str(self.value)
+        if len(self.history) > 1: return str(self.history)
+        else: return str(self.value)
 
     def __int__(self):
         return self.value
 
-
     def __lt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value < other
-        elif hasattr(other,"value"):
-            return self.value < other.value
-        else:
-            return self < other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value < other
+        elif hasattr(other,"value"): return self.value < other.value
+        else: return self < other
 
     def __le__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value <= other
-        elif hasattr(other,"value"):
-            return self.value <= other.value
-        else:
-            return self <= other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value <= other
+        elif hasattr(other,"value"): return self.value <= other.value
+        else: return self <= other
 
     def __eq__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value == other
-        elif hasattr(other,"value"):
-            return self.value == other.value
-        else:
-            return self == other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value == other
+        elif hasattr(other,"value"): return self.value == other.value
+        else: return self == other
 
     def __ne__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value != other
-        elif hasattr(other,"value"):
-            return self.value != other.value
-        else:
-            return self != other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value != other
+        elif hasattr(other,"value"): return self.value != other.value
+        else: return self != other
 
     def __gt__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value > other
-        elif hasattr(other,"value"):
-            return self.value > other.value
-        else:
-            return self > other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value > other
+        elif hasattr(other,"value"): return self.value > other.value
+        else: return self > other
 
     def __ge__(self,other):
-        if type(other) == type(3) or type(other) == type(3.0):
-            return self.value >= other
-        elif hasattr(other,"value"):
-            return self.value >= other.value
-        else:
-            return self >= other
+        if type(other) == type(3) or type(other) == type(3.0): return self.value >= other
+        elif hasattr(other,"value"): return self.value >= other.value
+        else: return self >= other
 
     def __cmp__(self,other):
         #  this function included for backwards compatibility
         #  As of 2.1, lists implement the "rich comparison"
         #  methods overloaded above.
-        if type(other) == type(3) or type(other) == type(3.0):
-            return cmp(self.value, other)
-        elif hasattr(other,"value"):
-            return cmp(self.value, other.value)
-        else:
-            return cmp(self,other)
+        if type(other) == type(3) or type(other) == type(3.0): return cmp(self.value, other)
+        elif hasattr(other,"value"): return cmp(self.value, other.value)
+        else: return cmp(self,other)
 
     def roll(self,min=1):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            self.value = random.randint(-1, 1)
-        else:
-            #self.value = random.randint(min, self.sides)
-            self.value = int(random.uniform(min, self.sides+1))
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f': self.value = random.randint(-1, 1)
+        else: self.value = int(random.uniform(min, self.sides+1))
         self.history = []
         self.history.append(self.value)
 
     def extraroll(self):
-        if isinstance(self.sides, basestring) and self.sides.lower() == 'f':
-            result = random.randint(-1, 1)
-        else:
-            #result = random.randint(1, self.sides)
-            result = int(random.uniform(1,self.sides+1))
-
+        if isinstance(self.sides, basestring) and self.sides.lower() == 'f': result = random.randint(-1, 1)
+        else: result = int(random.uniform(1,self.sides+1))
         self.value += result
         self.history.append(result)
 
@@ -444,8 +337,7 @@
     _rollers = {}
     def __new__(cls):
         it = cls.__dict__.get("__it__")
-        if it is not None:
-            return it
+        if it is not None: return it
         cls.__it__ = it = object.__new__(cls)
         return it
 
--- a/orpg/dieroller/rollers/7sea.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/7sea.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,7 +23,7 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: WOD die roller
 #
@@ -31,7 +31,7 @@
 # for compatibility with Mage die rolls.
 # Threshhold addition by robert t childers
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
--- a/orpg/dieroller/rollers/__init__.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/__init__.py	Sat Apr 24 08:37:20 2010 -0500
@@ -5,4 +5,4 @@
 
 for roller in os.listdir(os.path.abspath(os.path.dirname(__file__))):
     if roller.endswith('.py') and not roller.startswith('__'):
-        __import__("%s.%s" % (rollers, roller.split('.')[0]))
\ No newline at end of file
+        __import__("%s.%s" % (rollers, roller.split('.')[0]))
--- a/orpg/dieroller/rollers/alternity.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/alternity.py	Sat Apr 24 08:37:20 2010 -0500
@@ -18,20 +18,49 @@
 #
 # Changelog:
 #
-# v.1 original release JEC
-#
-# Traipse Release: 
-# The changes made in the Traipe release are intended to create a more direct connection
-# between the source and the intrepretor. IF, ELIF statements have been replaced with dictionaries,
+# v.1 original release JEC
+#
+# Traipse Release: 
+# The changes made in the Traipe release are intended to create a more direct connection
+# between the source and the intrepretor. IF, ELIF statements have been replaced with dictionaries,
 # unused objects have been replace with re-usable objects, and the code has been condensed.
-
+#
+# SEG: JAN 24 2010 - v.1.4 O'Flux Release:
+# Edits & Additions: fixed a few minor bugs; Damage roll & Display Issues.
+# Added Secondary Damage Calculation and Display. Fix all errors.
+# Added proper results for Critcal Successes with failure ==> final Result Ordinary Success
+# Removed reduntent Method to make parent class true with all others working as child.
+# Made all special output same colour codes font size. Cleaned out old commented lines.
+# Tested for Traipse on Win 7
+#
+#  Skill Check Example:
+#  [1d20.sk(12,-2)]
+#  OUTPUT Example:
+#  => [6,-3] = (3) AMAZING Success
+#
+#  Pistol, Laser; 0 step -- Attack Example:
+#  [1d20.at(12,0,(1d4+1,"w"),(1d6+1,"w"),(1d4,"m"))]
+#  OUTPUT Example:
+#  => [1,0] = (1) CRITICAL SUCCESS AMAZING HIT
+#  ===> Damage [4] = (4) mortal ======> Secondary Damage (2) stun / (2) wound
+#
+#  Action Check Example:
+#  [1d20.ac(14,-1)]
+#  OUTPUT Example:
+#   => ACTION CHECK : [18,-3] = (15) Marginal failure
+#   -1 Step make up bonus next Action Check
+#
+#
 
 import re
-
+
 from std import std
 from time import time, clock
 from orpg.dieroller.base import di, die_base, die_rollers
 
+##from orpg.tools.orpg_log import debug
+
+
 __version__ = "$Id: alternity.py,v 0.1 2003/01/02 12:00:00 cchriss Exp $"
 
 # Alternity stands for "Alternity system" 20 sided die plus mods
@@ -49,6 +78,9 @@
     def at(self,score,mod,dmgo,dmgg,dmga):
       return at(self,score,mod,dmgo,dmgg,dmga)
 
+    def ac(self,score,mod):
+        return ac(self,score,mod)
+
 die_rollers.register(alternity)
 
 class sk(std):
@@ -59,25 +91,29 @@
         self.mod = mod
 
     def getMod(self,mod=0):
-        m=0
-        mods = { -4: -di(12), -3: -di(8), -2:  -di(6), -1: -di(4), 1: -di(4),
-                2: di(6), 3: di(8), 4: di(12), 5: di(20)}
-        if mod in mods.keys(): m = mods[mod].value
+        m=0
+        mods = { -4: -di(12), -3: -di(8), -2:  -di(6), -1: -di(4), 1: di(4),
+                2: di(6), 3: di(8), 4: di(12), 5: di(20)} # SEG fix 1: di(4) #
+        if mod in mods.keys(): m = mods[mod].value
         elif mod <= -5: m=-di(20).value
         elif mod == 6:  m=di(20).value + di(20).value
         elif mod >= 7:  m=di(20).value + di(20).value + di(20).value
         return m
 
     def getRolLStr(self):
-        myStr = "[" + str(self.data[0])
+        myStr = "[" + str(self.data[0])
         self.d20 = self.sum()
-        amod = self.getMod(self.mod)
-        self.dieRoll = self.d20 + amod
+        self.amod = self.getMod(self.mod)
+
+##        varN = "self.amod"
+##        debug(varN)
+##        debug(self.amod)  ## seg added debug output
+        
+        self.dieRoll = self.d20 + self.amod
         for a in self.data[1:]:
             myStr += ","
             myStr += str(a)
-        myStr += "," + str(amod) + "] = (" + str(self.dieRoll) + ")"
-        if ( self.d20 == 1 ): self.success = 'CS'
+        myStr += "," + str(self.amod) + "] = (" + str(self.dieRoll) + ")"
         if ( self.dieRoll <= self.score / 4 ): self.success = 'A'
         elif ( self.dieRoll <= self.score / 2 ): self.success = 'G'
         elif ( self.dieRoll <= self.score ): self.success = 'O'
@@ -86,51 +122,127 @@
         return myStr
 
     def __str__(self):
-        myStr = self.getRolLStr()
-        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
-                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
-                    'A': " <b>AMAZING Success</b>",
-                    'G': " <b>Good Success</b>",
-                    'O': " <b>Ordinary Success</b>",
-                    'F': " <b>failure</b>"}
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b>",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING Success</font></b>",
+                    'G': " <b><font size=2 color='#306EFF'>Good Success</font></b>",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary Success</font></b>",
+                    'F': " <b><font size=2 color='#41627E'>failure</font></b>"}
+
+        if ( self.d20 == 1 ):  myStr += successes['CS'] # SEG Dec 19 2009
         myStr += successes[self.success]
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += "          final result ==> "
+            myStr += successes['O'] # SEG JAN 23 2010
         return myStr
 
-class at(sk):
-    ## Traipse Usage: The source I received had the damage rolls like this 1d6s, with the damage type a
-    ## letter that could be sliced from the roll. However, the roll is parsed before the letter can be
-    ## sliced from it, and with the letter attached it created an error.
-    ##
-    ## The Traipse method puts the damage type and the damage roll into a Tuple, ie (1d6, 's').
-    ## When uing this method you must include single or double quoutes around the damage type or the
+class at(sk):
+    ## Traipse Usage: The source I received had the damage rolls like this 1d6s, with the damage type a
+    ## letter that could be sliced from the roll. However, the roll is parsed before the letter can be
+    ## sliced from it, and with the letter attached it created an error.
+    ##
+    ## The Traipse method puts the damage type and the damage roll into a Tuple, ie (1d6, 's').
+    ## When using this method you must include single or double quoutes around the damage type or the
     ## software will treat it as an object.
+
     def __init__(self,source=[],sc=10, mod=0, dmgo="(1d6, 's')",dmgg="(1d6, 'w')",dmga="(1d6, 'm')"):
         sk.__init__(self,source,sc,mod)
         self.dmgo = dmgo
         self.dmgg = dmgg
         self.dmga = dmga
 
-    def getdmg(self,dmgroll):
-        astr = "===> Damage "
+    def getdmg(self,dmgroll):
+        astr = "<b>===></b> Damage "
         droll = str(dmgroll[0])
+        xyz = droll.split('(')
+        secD = (int(xyz[1][:-1])/2)   ## SEG* Calculate Secondary Damage
+
+##        varN = "secD"
+##        debug(varN)
+##        debug(secD)  ## seg added debug output
+
         dtype = dmgroll[1]
         astr += droll
-        if dtype=="s": astr += " stun"
-        elif dtype=="w": astr += " wound"
-        elif dtype=="m":astr += " mortal"
+        if dtype=="s": astr += " <b><font size=2 color='#52D017'>stun</font></b><BR>"
+        elif dtype=="w":
+            astr += " <b><font size=2 color='#C11B17'>wound</font></b>"+" <b>======></b> Secondary Damage ("+str(secD) \
+                    +") <b><font size=2 color='#52D017'>stun</font></b><BR>"  # SEG* Display Secondary Damage
+        elif dtype=="m":
+            astr += " <b><font size=2 color='#FF0000'>mortal</font></b>"+" <b>======></b> Secondary Damage ("+str(secD) \
+                    +") <b><font size=2 color='#52D017'>stun</font></b>"+" <b>/</b> ("+str(secD)+") <b><font size=2 color='#C11B17'>wound</font></b><BR>"  # SEG* Display Secondary Damage
         return astr
 
     def __str__(self):
-        myStr = self.getRolLStr()
-        successes = {'CS': " <b><font color='#00aa00'>CRITICAL SUCCESS</font></b>",
-                    'CF': " <b><font color='#ff0000'>CRITICAL FAILURE</font></b>",
-                    'A': " <b><font color='#00aa00'>AMAZING HIT</font></b> ",
-                    'G': " <b>Good HIT</b> ",
-                    'O': " <b>Ordinary HIT</b> ",
-                    'F': " <b>miss</b>"}
-        myStr += successes[self.success]
-        if self.success == 'A': myStr += self.getdmg(self.dmga)
-        elif self.success == 'G': myStr += self.getdmg(self.dmgg)
-        elif self.success == 'O': myStr += self.getdmg(self.dmgo)
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+        
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b>",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING HIT</font></b><BR> ",
+                    'G': " <b><font size=2 color='#306EFF'>Good HIT</font></b><BR> ",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary HIT</font></b><BR> ",
+                    'F': " <b><font size=2 color='#41627E'>miss</font></b>"}
+        if ( self.d20 == 1 ):
+            myStr += successes['CS'] # SEG Dec 19 2009
+
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += successes['F'] # SEG JAN 23 2010
+            myStr += "          final result ==> "
+            self.success = 'O'
+
+        myStr += successes[self.success]
+        if self.success == 'A': myStr += self.getdmg(self.dmga)
+        elif self.success == 'G': myStr += self.getdmg(self.dmgg)
+        elif self.success == 'O': myStr += self.getdmg(self.dmgo)
         return myStr
-
+
+class ac(sk):
+    def __init__(self,source=[],sc=10,mod=0):
+        sk.__init__(self,source,sc,mod)
+
+    def __str__(self):
+        myStr = self.getRolLStr()
+
+##        varN = "myStr"
+##        debug(varN)
+##        debug(myStr)  ## seg added debug output
+        
+        myStr = " <b><font color='#E42217'>ACTION CHECK : </font></b>"+myStr
+        successes = {'CS': " <b><font size=2 color='#8D38C9'>CRITICAL SUCCESS</font></b>",
+                    'CF': " <b><font size=2 color='#151B54'>CRITICAL FAILURE</font></b><BR> -2 Step make up bonus next Action Check",
+                    'A': " <b><font size=2 color='#E42217'>AMAZING Success</font></b>",
+                    'G': " <b><font size=2 color='#306EFF'>Good Success</font></b>",
+                    'O': " <b><font size=2 color='#52D017'>Ordinary Success</font></b>",
+                    'F': " <b><font size=2 color='#41627E'>Marginal failure</font></b>"}
+        if ( self.d20 == 1 ):  myStr += successes['CS'] # SEG Dec 19 2009
+        myStr += successes[self.success]
+        if ( self.d20 == 1 ) and (self.success == 'F') :
+            myStr += " final result ==> "
+            myStr += successes['O'] # SEG JAN 23 2010
+        if ( self.d20 != 1 ) and (self.success == 'F') :
+            myStr += "<BR> -1 Step make up bonus next Action Check"
+            
+        return myStr
+
+
+
+
+
+
+
+
+
+
+
+
+        
+
--- a/orpg/dieroller/rollers/d20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/d20.py	Sat Apr 24 08:37:20 2010 -0500
@@ -14,10 +14,10 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $
+#   $Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: d20 die roller
-__version__ = "$Id: d20.py,v 1.9 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 # d20 stands for "d20 system" not 20 sided die :)
 
@@ -30,8 +30,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
     def attack(self,AC,mod,critical):
         return d20attack(self,AC,mod,critical)
 
@@ -56,14 +54,9 @@
             myStr += ","
             myStr += str(a)
         myStr += "] = (" + str(self.sum()) + ")"
-
         myStr += " vs DC " + str(self.DC)
-
-        if self.is_success():
-            myStr += " Success!"
-        else:
-            myStr += " Failure!"
-
+        if self.is_success(): myStr += " Success!"
+        else: myStr += " Failure!"
         return myStr
 
 
@@ -86,8 +79,7 @@
         self.critical_roll = 0
         if self.data[0] >= self.critical and self.is_hit():
             self.critical_roll = die_base(20) + self.mod
-            if self.critical_roll.sum() >= self.AC:
-                self.critical_result = 1
+            if self.critical_roll.sum() >= self.AC: self.critical_result = 1
 
     def is_critical(self):
         return self.critical_result
@@ -101,15 +93,9 @@
             myStr += ","
             myStr += str(a)
         myStr += "] = (" + str(self.sum()) + ")"
-
         myStr += " vs AC " + str(self.AC)
-
-        if self.is_critical():
-            myStr += " Critical"
+        if self.is_critical(): myStr += " Critical"
+        if self.is_hit(): myStr += " Hit!"
+        else: myStr += " Miss!"
+        return myStr
 
-        if self.is_hit():
-            myStr += " Hit!"
-        else:
-            myStr += " Miss!"
-
-        return myStr
--- a/orpg/dieroller/rollers/gurps.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/gurps.py	Sat Apr 24 08:37:20 2010 -0500
@@ -51,11 +51,9 @@
 
 from time import time, clock
 import random
-
 from std import std
 from orpg.dieroller.base import *
 
-
 __version__ = "$Id: gurps.py,v 1.5 2007/05/06 16:42:55 digitalxero Exp $"
 
 # gurps
@@ -66,9 +64,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
-# Original msk roll renamed to be easier to understand/remember
     def skill(self,skill,mod):
         return gurpsskill(self,skill,mod)
 
@@ -133,8 +128,6 @@
         else:
             if self.sum() == 18:
                 myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
-#            elif self.sum() == 17 and (self.skill+self.mod < 16):
-#                myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
             elif self.sum() == 17:
                 if (self.skill+self.mod) < 16:
                     myStr += " or less <font color='#ff0000'><b>Critical Failure!</b></font> [B556]"
@@ -279,13 +272,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0]) 
+        for a in self.data[1:]:
+            myStr += "," 
+            myStr += str(a)
+        myStr += "] = " 
+        myStr += str(self.sum()) 
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
         elif self.sum() == 12:
@@ -310,13 +302,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0]) 
+        for a in self.data[1:]:
+            myStr += ","
+            myStr += str(a)
+        myStr += "] = "
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>The blow inflicts normal damage.</font> [B556]"
         elif self.sum() == 12 or self.sum() == 13:
@@ -347,13 +338,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]: 
+            myStr += ","
+            myStr += str(a) 
+        myStr += "] = "
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>You drop your weapon (& a <i>cheap</i> weapon breaks).</font> [B556]"
         elif self.sum() == 12 or self.sum() == 8:
@@ -386,13 +376,12 @@
         std.__init__(self,source)
 
     def __str__(self):
-        myStr = "[" + str(self.data[0]) #Variable myStr holds text and first we put a [ into it and then adds the first die rolled
-        for a in self.data[1:]:             #This is a for loop.  It will do the next two lines of code for every die (except the first die which we handled in the line above) in the roll.
-            myStr += ","                  #Adds a comma after each die
-            myStr += str(a)           #Adds the value of each die.
-        myStr += "] = "                 #Adds ] = to the end of the string (note the += means append to whatever is already stored in the variable
-        myStr += str(self.sum())          #Finally we add the actual result of the roll and myStr contains something like [3,2,1] = 6
-
+        myStr = "[" + str(self.data[0])
+        for a in self.data[1:]:
+            myStr += "," 
+            myStr += str(a)
+        myStr += "] = " 
+        myStr += str(self.sum())
         if self.sum() > 8 and self.sum() < 12:
             myStr += " <font color='#ff0000'>You lose your balance;  you can do nothing else (not even free actions) until next turn, and all defenses -2 until next turn.</font> [B557]"
         elif self.sum() == 12:
--- a/orpg/dieroller/rollers/hackmaster.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/hackmaster.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,7 +22,7 @@
 # Author: Ric Soard
 # Maintainer:
 # Version:
-#   $Id: hackmaster.py,v 0.4 2003/08/12
+#   $Id: hackmaster.py,v Traipse 'Ornery-Orc' prof.ebral Exp
 #
 # Description: special die roller for HackMaster(C)(TM) RPG
 #               has penetration damage - .damage(bonus,honor)
@@ -32,7 +32,7 @@
 #
 #
 
-__version__ = "$Id: hackmaster.py,v 1.8 2006/11/15 12:11:22 digitalxero Exp $"
+__version__ = "$Id: hackmaster.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import random
 from std import std
@@ -120,7 +120,6 @@
         #this is a static die that adds honor, we want high rolls so it's +1
         self.append(static_di(self.hon))
 
-
     def check_crit(self):
         if self.data[0] == self.data[0].sides:
             self.crit = 1
@@ -170,7 +169,6 @@
         myStr += " Example [1d8.severity(1)] <br />"
         myStr += " .help() : <br />"
         myStr += " displays this message <br />"
-
         return myStr
 
 # the severity roll is for critical resolution. The die is rerolled and added
@@ -185,7 +183,6 @@
         self.CheckReroll()
         self.append(static_di(self.hon))
 
-
     def __str__(self):
         myStr = "[Severity Dice, Honor]" + " [" + str(self.data[0])
         for a in self.data[1:]:
@@ -205,7 +202,6 @@
         result = int(random.uniform(1,self.data[num].sides+1))
         self.data[num].value += (((result - 1) * neg) + self.hon)
         self.data[num].history.append(((result - 1) * neg) + self.hon)
-        if result >= self.data[num].sides:
-            self.crit_chain(num,1)
-        if result == 1:
-            self.crit_chain(num,-1)
+        if result >= self.data[num].sides: self.crit_chain(num,1)
+        if result == 1: self.crit_chain(num,-1)
+
--- a/orpg/dieroller/rollers/hero.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/hero.py	Sat Apr 24 08:37:20 2010 -0500
@@ -29,11 +29,10 @@
 #
 # v.1 original release DJM
 
-__version__ = "$Id: hero.py,v 1.15 2006/11/04 21:24:19 digitalxero Exp $"
+__version__ = "$Id: hero.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from time import time, clock
 import random
-
 from std import std
 from orpg.dieroller.base import *
 
@@ -45,7 +44,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
 
     def k(self,mod):
         return herok(self,mod)
@@ -73,7 +71,6 @@
         self.cv = cv
         self.mod = mod
 
-
     def __str__(self):
         myStr = "[" + str(self.data[0])
         for a in self.data[1:]:
@@ -110,15 +107,10 @@
         modSum = self.sum()-self.mod
         myStr += " = (" + str(modSum) + ")"
         myStr += " vs " + str(self.sk)
-
-        if self.is_success():
-            myStr += " or less <font color='#ff0000'>Success!"
-        else:
-            myStr += " or less <font color='#ff0000'>Failure!"
-
+        if self.is_success(): myStr += " or less <font color='#ff0000'>Success!"
+        else: myStr += " or less <font color='#ff0000'>Failure!"
         Diff = self.sk - modSum
         myStr += " by " + str(Diff) +" </font>"
-
         return myStr
 
 class herok(std):
@@ -230,3 +222,4 @@
         myStr += " <b>Body</b> and "
         myStr += "(<font color='#ff0000'><b>" + str(int(round(self.sum()))) + "</b></font>) <b>Stun</b>"
         return myStr
+
--- a/orpg/dieroller/rollers/mythos.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/mythos.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,9 +23,9 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-# Description: WOD die roller
+# Description: Mythos die roller
 #
 # Targetthr is the Threshhold target
 # for compatibility with Mage die rolls.
@@ -34,7 +34,7 @@
 from std import std
 from orpg.dieroller.base import *
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 class mythos(std):
@@ -85,7 +85,7 @@
             else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
         return myStr
 
-    def non_stdDie(self, s): ## Puu-san
+    def non_stdDie(self, s):
         num_sides = s.split('v')
         if len(num_sides) > 1: 
             num_sides; num = num_sides[0]; sides = num_sides[1]
--- a/orpg/dieroller/rollers/runequest.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/runequest.py	Sat Apr 24 08:37:20 2010 -0500
@@ -52,7 +52,7 @@
 #  o Added Sorcery Fumble table to sorcery spell roller
 #
 
-__version__ = "$Id: runequest.py,v 1.4 2006/11/15 12:11:22 digitalxero Exp $"
+__version__ = "$Id: runequest.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from time import time, clock
 import random
@@ -68,8 +68,6 @@
     def __init__(self,source=[]):
         std.__init__(self,source)
 
-# these methods return new die objects for specific options
-
     def skill(self,sk,mod,ma):
         return rqskill(self,sk,mod,ma)
 
@@ -112,24 +110,20 @@
 
     def __str__(self):
         myStr = "Unrestricted Training"
-
         if self.s == 0:
             myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             myStr = "Training: "
-
             while self.s < self.f and self.s < 75:
                 cost   += self.s * 5
                 time   += self.s * 1
                 self.s += random.uniform(1,4) + 1
-
             myStr  = "Training completed:\n"
             myStr += "\tCost(" + str(int(cost)) + ")\n"
             myStr += "\tTime(" + str(int(time)) + ")\n"
             myStr += "\tSkill(" + str(int(self.s)) + ")"
-
         return myStr
 
 
@@ -150,30 +144,24 @@
 
     def __str__(self):
         myStr = ""
-
         if self.sk == 0 and self.cost >= 50:
             myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             icost = self.sk * 5
-
             myStr = "Training: "
-
             while (cost + icost) < self.cost:
                 if self.sk >= 75:
                     break
-
                 cost += icost
                 time += self.sk * 1
                 self.sk += random.uniform(1,4) + 1
                 icost = self.sk * 5
-
             myStr  = "Training completed: "
             myStr += "Cost(" + str(int(cost)) + ") "
             myStr += "Time(" + str(int(time)) + ") "
             myStr += "Skill(" + str(int(self.sk)) + ")"
-
         return myStr
 
 
@@ -194,30 +182,24 @@
 
     def __str__(self):
         myStr = ""
-
         if self.sk == 0 and self.time >= 20:
             myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
         else:
             cost  = 0
             time  = 0
             itime = self.sk * 1
-
             myStr = "Trainingsss: "
-
             while (time + itime) < self.time:
                 if self.sk >= 75:
                     break
-
                 cost += self.sk * 5
                 time += itime
                 self.sk += random.uniform(1,4) + 1
                 itime = self.sk * 5
-
             myStr  = "Training completed: "
             myStr += "Cost(" + str(int(cost)) + ") "
             myStr += "Time(" + str(int(time)) + ") "
             myStr += "Skill(" + str(int(self.sk)) + ")"
-
         return myStr
 
 #  RQ Skill Roll
@@ -281,7 +263,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font></b>"
         elif self.is_critical():
@@ -294,10 +275,8 @@
             myStr += " <font color=blue>Success!</font>"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 #
@@ -341,7 +320,6 @@
         return (  self.sum() >= final_fum )
 
     def __str__(self):
-
         # get fumble roll result in case needed
         fum_roll = random.randint(1,100)
 
@@ -359,7 +337,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif self.is_critical() and self.is_riposte():
@@ -378,10 +355,8 @@
             myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 # RQ Dodge Roll
@@ -424,7 +399,6 @@
         return (  self.sum() >= final_fum )
 
     def __str__(self):
-
         # get fumble roll result in case needed
         fum_roll = random.randint(1,100)
 
@@ -442,7 +416,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif self.is_critical() and self.is_riposte():
@@ -461,14 +434,11 @@
             myStr += " <font color=blue>Success!</font> Damage dodged</b>"
         else:
             myStr += " <font color=red>Failure!</font>"
-
         Diff = self.sk - modSum
         myStr += " </font>"
-
         return myStr
 
 
-
 #
 # RQ Attack Roll
 #
@@ -535,7 +505,6 @@
             myStr += "<B>Head</B>"
         hit_loc = myStr
 
-
         # get normal damage in case needed
         norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
         norm_damage_string  = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
@@ -563,7 +532,6 @@
         # build output string
         myStr = " (" + str(modSum) + ")"
         myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
-
         if self.is_fumble():
             myStr += " <b><font color=red>Fumble!</font>  See Fumble Chart [" + str(fum_roll) + "]</b>"
         elif (self.is_supercritical() and self.is_success()):
@@ -578,7 +546,6 @@
             myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
         else:
             myStr += " <font color=red>Failure!</font>"
-
         return myStr
 
 #
@@ -691,6 +658,5 @@
         myStr += "Intensity(-3):["      + str( self.int      ) + "], "
         myStr += "Accelerate(-5):["     + str( self.acc      ) + "], "
         myStr += "Multispell(-10):["    + str( self.mlt      ) + "] ---"
-
         return myStr
 
--- a/orpg/dieroller/rollers/savage.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/savage.py	Sat Apr 24 08:37:20 2010 -0500
@@ -19,7 +19,7 @@
 # Permission was granted by Pinnacle to reprint the result descriptions from their tables on Apr 20, 2006 by Simon Lucas
 #
 
-__version__ = "$Id: savage.py,v 1.2 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: savage.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import string
 from random import *
--- a/orpg/dieroller/rollers/std.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/std.py	Sat Apr 24 08:37:20 2010 -0500
@@ -3,8 +3,8 @@
 class std(die_base):
     name = "std"
 
-    def __init__(self,source=[]):
-        die_base.__init__(self,source)
+    def __init__(self, source=[]):
+        die_base.__init__(self, source)
 
     #  Examples of adding member functions through inheritance.
 
@@ -19,30 +19,27 @@
         result.reverse()
         return result
 
-    def takeHighest(self,num_dice):
+    def takeHighest(self, num_dice):
         return self.descending()[:num_dice]
 
     def takeLowest(self,num_dice):
         return self.ascending()[:num_dice]
 
-    def extra(self,num):
+    def extra(self, num):
         for i in range(len(self.data)):
             if self.data[i].lastroll() >= num:
                 self.data[i].extraroll()
         return self
 
-    def open(self,num):
-        if num <= 1:
-            self
+    def open(self, num):
+        if num <= 1: self
         done = 1
         for i in range(len(self.data)):
             if self.data[i].lastroll() >= num:
                 self.data[i].extraroll()
                 done = 0
-        if done:
-            return self
-        else:
-            return self.open(num)
+        if done: return self
+        else: return self.open(num)
 
     def minroll(self,min):
         for i in range(len(self.data)):
@@ -50,13 +47,12 @@
                 self.data[i].roll(min)
         return self
 
-    def each(self,mod):
+    def each(self, mod):
         mod = int(mod)
         for i in range(len(self.data)):
             self.data[i].modify(mod)
         return self
 
-
     def vs(self, target):
         for dn in self.data:
             dn.target = target
@@ -72,12 +68,10 @@
         for dn in self.data:
             setValue = reduce( lambda x, y : int(x)+int(y), dn.history )
             if dn.target:
-                if setValue >= dn.target:
-                    retValue += 1
-
+                for dv in dn.history:
+                    if int(dv) >= dn.target: retValue += 1
             else:
                 retValue += setValue
-
         return retValue
 
-die_rollers.register(std)
\ No newline at end of file
+die_rollers.register(std)
--- a/orpg/dieroller/rollers/trinity.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/trinity.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,7 +23,7 @@
 # Author: Jacob Matthew, Talisan Creations
 # Maintainer:
 # Version:
-#   $Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $
+#   $Id: trinity.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Aeon Trinity die roller
 # Modified from the WoD dieroller "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
@@ -32,7 +32,7 @@
 # Threshhold addition by robert t childers
 # Threshhold functionality removed, some tags remain in code.
 
-__version__ = "$Id: trinity.py,v 1.2 2007/05/05 05:30:10 digitalxero Exp $"
+__version__ = "$Id: trinity.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
@@ -85,4 +85,4 @@
 
         return myStr
 
-die_rollers.register(trinity)
\ No newline at end of file
+die_rollers.register(trinity)
--- a/orpg/dieroller/rollers/wfrpg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wfrpg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,13 +23,13 @@
 # Author: Prof. Ebral, TaS (Traipse)
 # Maintainer:
 # Version:
-#   $Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $
+#   $Id: wfrpg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Warhammer Fantasy Roleplay Dice Roller die roller
 # Comissioned by Puu-san
 #
 
-__version__ = "$Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $"
+__version__ = "$Id: wfrpg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 import random
--- a/orpg/dieroller/rollers/wod.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wod.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,7 +23,7 @@
 # Author: OpenRPG Dev Team
 # Maintainer:
 # Version:
-#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#   $Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: WOD die roller
 #
@@ -31,7 +31,7 @@
 # for compatibility with Mage die rolls.
 # Threshhold addition by robert t childers
 
-__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+__version__ = "$Id: wod.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from std import std
 from orpg.dieroller.base import *
--- a/orpg/dieroller/rollers/wodex.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/rollers/wodex.py	Sat Apr 24 08:37:20 2010 -0500
@@ -34,7 +34,7 @@
 from std import std
 from orpg.dieroller.base import *
 
-__version__ = "$Id: wodex.py,v 1.9 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: wodex.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 class wodex(std):
     name = "wodex"
--- a/orpg/dieroller/utils.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/dieroller/utils.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,12 +22,12 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $
+#   $Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: Classes to help manage the die roller
 #
 
-__version__ = "$Id: utils.py,v 1.22 2007/05/05 05:30:10 digitalxero Exp $"
+__version__ = "$Id: utils.py,v Traipse 'Ornery-Orc' prof.ebral Exp  Exp $"
 
 import re
 
@@ -56,8 +56,7 @@
         return die_rollers.keys()
 
     def stdDieToDClass(self, match):
-        s = match.group(0)
-        self.mod = str(match.string[len(s):])
+        s = match.group(0); self.eval = str(match.string)
         num_sides = s.split('d')
         if len(num_sides) > 1: 
             num_sides; num = num_sides[0]; sides = num_sides[1]
@@ -66,13 +65,17 @@
                 if int(num) > 100 or int(sides) > 10000: return None
             except: pass
             ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
-                    sides.strip(), '))'+self.mod]
-            s =  ''.join(ret); s = str(eval(s)); return s ## Moved eval here for portability.
+                    sides.strip(), '))']
+            s =  ''.join(ret)
+            self.eval = s
+            return s
+
         ## Portable Non Standard Die Characters #Prof-Ebral
-        else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); self.mod = ''; return s
+        else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); return s
 
     #  Use this to convert ndm-style (3d6) dice to d_base format
     def convertTheDieString(self,s):
+        self.result = ''
         reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+")
         (result, num_matches) = reg.subn(self.stdDieToDClass, s)
         if num_matches == 0 or result is None:
@@ -83,15 +86,19 @@
                 test = eval(s2)
                 return s2
             except Exception, e: print e; pass"""
+            self.result = result
             try: return self.do_math(s)
             except: pass
         return result
 
     def do_math(self, s):
-        self.mod = ''
         return str(eval(s))
 
     def proccessRoll(self, s):
-        v = str(self.convertTheDieString(s))
-        return v[:len(v)-len(self.mod)]
+        v = self.convertTheDieString(s)
+        try: b = str(eval(v))
+        except: 
+            if v == self.eval: b = s
+            else: b = str(v) ##Fail safe for non standard dice.
+        return b
 
--- a/orpg/gametree/nodehandlers/StarWarsd20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/StarWarsd20.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis; Mark Twombley
 # Maintainer: Mark Twombley
 # Version:
-#   $Id: StarWarsd20.py,v 1.18 2006/11/15 12:11:23 digitalxero Exp $
+#   $Id: StarWarsd20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the StarWarsd20 nodehanlers
 #
 
-__version__ = "$Id: StarWarsd20.py,v 1.18 2006/11/15 12:11:23 digitalxero Exp $"
+__version__ = "$Id: StarWarsd20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from containers import *
--- a/orpg/gametree/nodehandlers/chatmacro.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/chatmacro.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: chatmacro.py,v 1.15 2006/11/15 12:11:23 digitalxero Exp $
+#   $Id: chatmacro.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the form based nodehanlers
 #
 
-__version__ = "$Id: chatmacro.py,v 1.15 2006/11/15 12:11:23 digitalxero Exp $"
+__version__ = "$Id: chatmacro.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 
--- a/orpg/gametree/nodehandlers/containers.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/containers.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: containers.py,v 1.43 2007/08/08 19:17:17 digitalxero Exp $
+#   $Id: containers.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the container nodehandlers
 #
@@ -282,7 +282,7 @@
 
     def build_splitter_wnd(self, parent, mode):
         self.split = self.xml.get("horizontal")
-        self.pane = splitter_panel(parent, self)
+        self.pane = splitter_panel(parent, self, mode)
         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)
@@ -291,7 +291,6 @@
         self.bestSizey = -1
         self.tree.traverse(self.mytree_node, self.doSplit, mode, False) 
         self.pane.sizer.Add(self.splitter, 1, wx.EXPAND)
-        if mode != 1: self.pane.hozCheck.Hide()
         self.pane.SetSize((self.bestSizex, self.bestSizey))
         self.pane.Layout()
         parent.SetSize(self.pane.GetSize())
@@ -314,28 +313,29 @@
         return 1
 
 class splitter_panel(wx.Panel):
-    def __init__(self, parent, handler):
+    def __init__(self, parent, handler, mode):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
-
-        self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
-        hoz = self.handler.xml.get("horizontal")
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        if mode == 0: self.title = wx.StaticText(self, 1, handler.xml.get('name'))
+        elif mode == 1: self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
+        #self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
 
-        if hoz == '1': self.hozCheck.SetValue(True)
-        else: self.hozCheck.SetValue(False)
+        if mode == 1:
+            self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
+            hoz = self.handler.xml.get("horizontal")
+            if hoz == '1': self.hozCheck.SetValue(True)
+            else: self.hozCheck.SetValue(False)
 
-        sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
-        sizer.Add(self.title, 0)
-        sizer.Add(self.hozCheck, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,0))
+        if mode == 1: self.sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.sizer.Add(self.title, 0)
+        if mode == 1: self.sizer.Add(self.hozCheck, 0, wx.EXPAND)
+        self.sizer.Add(wx.Size(10,0))
 
-        self.sizer = sizer
         self.SetSizer(self.sizer)
         self.SetAutoLayout(True)
         self.Bind(wx.EVT_TEXT, self.on_text, id=1)
-        self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
+        if mode == 1: self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
 
     def on_check_box(self,evt):
         state = self.hozCheck.GetValue()
--- a/orpg/gametree/nodehandlers/core.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/core.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,14 +21,15 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: core.py,v 1.49 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: core.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the core nodehanlers
 #
 
-__version__ = "$Id: core.py,v 1.49 2007/12/07 20:39:48 digitalxero Exp $"
+__version__ = "$Id: core.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from nodehandler_version import NODEHANDLER_VERSION
+from orpg.tools.InterParse import Parse
 
 try:
     from orpg.orpg_windows import *
@@ -54,7 +55,6 @@
         self.xml = xml
         self.mytree_node = tree_node
         self.tree = component.get('tree')
-        #self.tree = component.get('tree_fs')
         self.frame = component.get('frame')
         self.chat = component.get('chat')
         self.drag = True
@@ -282,7 +282,7 @@
     def get_html_panel(self,parent):
         html_str = "<html><body bgcolor=\"#FFFFFF\" >"+self.tohtml()+"</body></html>"
         wnd = wx.html.HtmlWindow(parent,-1)
-        html_str = self.chat.ParseDice(html_str)
+        html_str = Parse.Dice(html_str)
         wnd.SetPage(html_str)
         return wnd
 
@@ -386,7 +386,8 @@
 
     def on_ldclick(self,evt):
         file_name = self.file_node.get("name")
-        self.tree.insert_xml(open(orpg.dirpath.dir_struct["nodes"] + file_name,"r").read())
+        try: self.tree.insert_xml(open(orpg.dirpath.dir_struct["nodes"] + file_name,"r").read())
+        except: wx.MessageBox('Invalid File', 'Error')
         return 1
 
     def on_design(self,evt):
--- a/orpg/gametree/nodehandlers/d20.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/d20.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: d20.py,v 1.30 2007/05/22 00:50:57 digitalxero Exp $
+#   $Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the d20 nodehanlers
 #
 
-__version__ = "$Id: d20.py,v 1.30 2007/05/22 00:50:57 digitalxero Exp $"
+__version__ = "$Id: d20.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from containers import *
@@ -34,6 +34,7 @@
 from xml.etree.ElementTree import ElementTree, Element, iselement
 from xml.etree.ElementTree import fromstring, tostring, parse, XML
 from orpg.tools.orpg_log import debug
+from orpg.tools.InterParse import Parse
 
 D20_EXPORT = wx.NewId()
 ############################
@@ -991,9 +992,9 @@
             for i in range( 0, len( bab ) ):
                 if bab[i] > 0 or i == 0:
                     attack_roll_str = '[1d20%+d]' % (bab[i] + attack_mod)
-                    attack_roll_parsed = self.chat.ParseDice( attack_roll_str )
+                    attack_roll_parsed = Parse.Dice( attack_roll_str )
                     damage_roll_str = '[%dd%d%+d%s]' % (num_damage_dice, damage_die, damage_mod, extra_damage)
-                    damage_roll_parsed = self.chat.ParseDice( damage_roll_str )
+                    damage_roll_parsed = Parse.Dice( damage_roll_str )
                     txt = '%s (%s): %s ===> Damage: %s' \
                           % (name, bab_attributes[i], attack_roll_parsed, damage_roll_parsed)
                     self.chat.Post( txt, True, True )
--- a/orpg/gametree/nodehandlers/dnd3e.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/dnd3e.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis & Digitalxero
 # Maintainer: leadb
 # Version:
-#   $Id: dnd3e.py,v 1.33 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: dnd3e.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the dnd3e nodehanlers
 #
@@ -261,7 +261,6 @@
         n_list = self.xml.getchildren()
         html_str = "<table width=100% border=1 ><tr BGCOLOR=#E9E9E9 ><th>General Information</th></tr><tr><td>"
         for n in n_list:
-            debug(n)
             html_str += "<B>"+n.tag.capitalize() +":</B> "
             html_str += n.text + ", "
         html_str = html_str[:len(html_str)-2] + "</td></tr></table>"
@@ -377,12 +376,10 @@
             value = self.lang.GetValue()
         for node in self.n_list:
             if node.tag == nodeName:
-                debug(node)
                 node.text = value
 
     def saveMoney(self, row, col):
         value = self.grid.GetCellValue(row, col)
-        debug(self.n_list[row])
         self.n_list[row].text = value
 
     def on_cell_change(self, evt):
@@ -2271,12 +2268,10 @@
                 self.xml.remove(self.n_list[i])
 
     def on_add(self,evt):
-        debug()
         if not self.temp_dom:
             tree = parse(dir_struct["dnd3e"]+"dnd3espells.xml")
             xml_dom = tree.getroot()
             self.temp_dom = xml_dom
-        debug(self.temp_dom)
         f_list = self.temp_dom.findall('spell')
         opts = []
         #lvl = int(dnd3e_char_child.get_char_lvl('level'))
@@ -2667,12 +2662,10 @@
                 self.xml.remove(self.n_list[i])
 
     def on_add(self,evt):
-        debug()
         if not self.temp_dom:
             tree = parse(dir_struct["dnd3e"]+"dnd3epowers.xml")
             xml_dom = tree.getroot()
             self.temp_dom = xml_dom
-        debug(self.temp)
         f_list = self.temp_dom.findall('power')
         opts = []
         for f in f_list:
--- a/orpg/gametree/nodehandlers/forms.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/forms.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,18 +21,19 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: forms.py,v 1.53 2007/04/21 23:00:51 digitalxero Exp $
+#   $Id: forms.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the form based nodehanlers
 #
 
-__version__ = "$Id: forms.py,v 1.53 2007/04/21 23:00:51 digitalxero Exp $"
+__version__ = "$Id: forms.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from containers import *
 import orpg.minidom as minidom
 from orpg.orpg_xml import xml
 from wx.lib.scrolledpanel import ScrolledPanel
 from orpg.tools.settings import settings
+from orpg.tools.InterParse import Parse
 
 def bool2int(b):
     #in wxPython 2.5+, evt.Checked() returns True or False instead of 1.0 or 0.
@@ -262,16 +263,16 @@
 
     def on_send(self, evt):
         txt = self.text.GetValue()
-        txt = self.chat.ParseMap(txt, self.handler.xml)
-        txt = self.chat.ParseParent(txt, self.handler.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.handler.xml)
         if not self.handler.is_raw_send():
-            self.chat.ParsePost(self.handler.tohtml(), True, True)
+            Parse.Post(self.handler.tohtml(), True, True)
             return 1
         actionlist = txt.split("\n")
         for line in actionlist:
+            line = Parse.ParseLogic(line, self.handler.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    self.chat.ParsePost(line, True, True)
+                    Parse.Post(line, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -595,18 +596,16 @@
 
     def on_send_to_chat(self, evt):
         txt = self.get_selected_text()
-        txt = self.chat.ParseMap(txt, self.xml)
-        txt = self.chat.ParseParent(txt, self.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.xml)
         if not self.is_raw_send():
-            self.chat.ParsePost(self.tohtml(), True, True)
+            Parse.Post(self.tohtml(), True, True)
             return 1
         actionlist = self.get_selections_text()
         for line in actionlist:
-            line = self.chat.ParseMap(line, self.xml)
-            line = self.chat.ParseParent(line, self.xml.get('map'))
+            line = Parse.ParseLogic(line, self.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    self.chat.ParsePost(line, True, True)
+                    Parse.Post(line, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -754,7 +753,7 @@
     def on_add(self,evt):
         self.dlg = wx.Frame(self, -1, 'Text', size=(300,150))
         edit_panel = wx.Panel(self.dlg, -1)
-        sizer = wx.GridBagSizer(1, 2)
+        sizer = wx.GridBagSizer(1, 1)
         edit_panel.SetSizer(sizer)
         caption_text = wx.StaticText(edit_panel, -1, 'Caption')
         self.caption_entry = wx.TextCtrl(edit_panel, -1, '')
@@ -764,12 +763,17 @@
         button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
         button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
         sizer.Add(caption_text, (0,0))
-        sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(self.caption_entry, (0,1), span=(1,4), flag=wx.EXPAND)
         sizer.Add(value_text, (1,0))
-        sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(self.value_entry, (1,1), span=(1,4), flag=wx.EXPAND)
         sizer.Add(button_ok, (3,0))
         sizer.Add(button_cancel, (3,1))
         sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+        sizer.AddGrowableCol(3)
+        sizer.AddGrowableRow(2)
+        self.dlg.SetSize((275, 125))
+        self.dlg.SetMinSize((275, 125))
+        self.dlg.Layout()
         self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
         self.Bind(wx.EVT_BUTTON, self.on_add_option, id=wx.ID_OK)
         self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
@@ -883,12 +887,17 @@
             button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
             button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
             sizer.Add(caption_text, (0,0))
-            sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(self.caption_entry, (0,1), span=(1,4), flag=wx.EXPAND)
             sizer.Add(value_text, (1,0))
-            sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(self.value_entry, (1,1), span=(1,4), flag=wx.EXPAND)
             sizer.Add(button_ok, (3,0))
             sizer.Add(button_cancel, (3,1))
             sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+            sizer.AddGrowableCol(3)
+            sizer.AddGrowableRow(2)
+            self.dlg.SetSize((275, 125))
+            self.dlg.SetMinSize((275, 125))
+            self.dlg.Layout()
             self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
             self.Bind(wx.EVT_BUTTON, self.on_edit_ok, id=wx.ID_OK)
             self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
--- a/orpg/gametree/nodehandlers/map_miniature_nodehandler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/map_miniature_nodehandler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Andrew Bennett
 # Maintainer:
 # Version:
-#   $Id: map_miniature_nodehandler.py,v 1.17 2007/12/07 20:39:48 digitalxero Exp $
+#   $Id: map_miniature_nodehandler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for miniature images
 #
--- a/orpg/gametree/nodehandlers/minilib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/minilib.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: minilib.py,v 1.28 2007/04/22 22:00:18 digitalxero Exp $
+#   $Id: minilib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for a collection of miniatures.
 #
 
-__version__ = "$Id: minilib.py,v 1.28 2007/04/22 22:00:18 digitalxero Exp $"
+__version__ = "$Id: minilib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 """Nodehandler for collections of miniatures.  User can add, delete, edit
 miniatures as sending them to the map singly or in batches.
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,15 +21,17 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $
+#   $Id: rpg_grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the grid nodehanlers
 #
 
-__version__ = "$Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $"
+__version__ = "$Id: rpg_grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from core import *
 from forms import *
+from orpg.tools.orpg_log import debug
+from orpg.tools.InterParse import Parse
 
 class rpg_grid_handler(node_handler):
     """ Node handler for rpg grid tool
@@ -87,16 +89,20 @@
                 html_str += "<td >"
                 text = c.text
                 if text == None or text == '': text = '<br />'
+                s = Parse.ParseLogic(text, self.xml)
+                s = Parse.Normalize(s)
+                try: text = str(eval(s))
+                except: text = s
                 html_str += text + "</td>"
             html_str += "</tr>"
         html_str += "</table>"
         return html_str
 
     def get_design_panel(self,parent):
-        return rpg_grid_edit_panel(parent,self)
+        return rpg_grid_edit_panel(parent, self)
 
     def get_use_panel(self,parent):
-        return rpg_grid_panel(parent,self)
+        return rpg_grid_panel(parent, self)
 
     def get_size_constraint(self):
         return 1
@@ -194,7 +200,8 @@
         to begin editing.  Set the focus to the edit control.
         *Must Override*
         """
-        self.startValue = grid.GetTable().GetValue(row, col)
+        #self.startValue = grid.GetTable().GetValue(row, col)
+        self.startValue = grid.get_value(row, col)
         self._tc.SetValue(self.startValue)
         self._tc.SetInsertionPointEnd()
         self._tc.SetFocus()
@@ -213,7 +220,6 @@
         if val != self.startValue:
             changed = True
             grid.GetTable().SetValue(row, col, val) # update the table
-
         self.startValue = ''
         self._tc.SetValue('')
         return changed
@@ -265,11 +271,11 @@
 
 class rpg_grid(wx.grid.Grid):
     """grid for attacks"""
-    def __init__(self, parent, handler):
+    def __init__(self, parent, handler, mode):
         wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
         self.parent = parent
         self.handler = handler
-
+        self.mode = mode
         self.RegisterDataType(wx.grid.GRID_VALUE_STRING, wx.grid.GridCellStringRenderer(),MyCellEditor())
 
         self.rows = handler.grid.findall('row')
@@ -286,7 +292,6 @@
         self.Bind(wx.grid.EVT_GRID_COL_SIZE, self.on_col_size)
         self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_leftdclick)
 
-
     def on_leftdclick(self,evt):
         if self.CanEnableCellControl(): self.EnableCellEditControl()
 
@@ -304,6 +309,7 @@
         cells = self.rows[row].findall('cell')
         cells[col].text = value
         if col == 0: self.handler.refresh_rows()
+        for i in range(0,len(self.rows)): self.refresh_row(i)
 
     def set_col_widths(self):
         cells = self.rows[0].findall('cell')
@@ -313,13 +319,17 @@
                 self.SetColSize(i,size)
             except: continue
 
-    def refresh_row(self,rowi):
+    def refresh_row(self, rowi):
         cells = self.rows[rowi].findall('cell')
         for i in range(0,len(cells)):
             text = cells[i].text
             if text == None or text == '':
                 text = ''
                 cells[i].text = text
+            if self.mode == 0:
+                s = Parse.ParseLogic(text, self.handler.xml)
+                try: text = str(eval(s))
+                except: text = s
             self.SetCellValue(rowi,i,text)
 
     def add_row(self,evt=None):
@@ -359,6 +369,10 @@
         self.DeleteCols(num-1,1)
         self.set_col_widths()
 
+    def get_value(self, row, col):
+        cells = self.rows[row].findall('cell')
+        return cells[col].text
+
 
 G_TITLE = wx.NewId()
 GRID_BOR = wx.NewId()
@@ -366,7 +380,7 @@
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
-        self.grid = rpg_grid(self, handler)
+        self.grid = rpg_grid(self, handler, mode=0)
         label = handler.xml.get('name')
         self.main_sizer = wx.BoxSizer(wx.VERTICAL)
         self.main_sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
@@ -388,7 +402,7 @@
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
         self.parent = parent
-        self.grid = rpg_grid(self,handler)
+        self.grid = rpg_grid(self,handler, mode=1)
         self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Grid"), wx.VERTICAL)
 
         self.title = wx.TextCtrl(self, G_TITLE, handler.xml.get('name'))
@@ -462,6 +476,8 @@
         complete = complete[:len(complete)-2] + '::'+'('+row+','+col+')'+complete[len(complete)-2:]
         col = self.grid.GetGridCursorCol()
         row = self.grid.GetGridCursorRow()
+        temp_value = self.grid.GetCellValue(row, col)
+        complete = temp_value + complete
         self.grid.SetCellValue(row, col, complete)
         cells = self.grid.rows[row].findall('cell')
         cells[col].text = complete
@@ -505,6 +521,8 @@
                 else:
                     col = self.grid.GetGridCursorCol()
                     row = self.grid.GetGridCursorRow()
+                    temp_value = self.grid.GetCellValue(row, col)
+                    complete = temp_value + complete
                     self.grid.SetCellValue(row, col, complete)
                     cells = self.grid.rows[row].findall('cell')
                     cells[col].text = complete
@@ -527,3 +545,15 @@
         if txt != "":
             self.handler.xml.set('name',txt)
             self.handler.rename(txt)
+
+    def refresh_row(self,rowi):
+        cells = self.rows[rowi].findall('cell')
+        for i in range(0,len(cells)):
+            text = cells[i].text
+            #s = component.get('chat').ParseMap(s, self.handler.xml)
+            #try: text = str(eval(s))
+            #except: text = s
+            if text == None or text == '':
+                text = ''
+                cells[i].text = text
+            self.SetCellValue(rowi,i,text)
--- a/orpg/gametree/nodehandlers/voxchat.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/gametree/nodehandlers/voxchat.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: voxchat.py,v 1.37 2007/05/06 16:42:55 digitalxero Exp $
+#   $Id: voxchat.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for alias.
 #
 
-__version__ = "$Id: voxchat.py,v 1.37 2007/05/06 16:42:55 digitalxero Exp $"
+__version__ = "$Id: voxchat.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import re, os, string, core
 
@@ -53,7 +53,7 @@
     def __init__(self, xml_dom, tree_node):
         core.node_handler.__init__( self, xml_dom, tree_node)
         self.node = xml_dom
-        self.xml = component.get('xml')
+        #self.xml = component.get('xml')
 
     def get_design_panel( self, parent ):
         aliasLib = component.get('alias')
--- a/orpg/main.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/main.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,13 +21,13 @@
 # File: main.py
 # Author: Chris Davis
 # Maintainer:
-# Version:
-#   $Id: main.py,v 1.153 2008/01/24 03:52:03 digitalxero Exp $
+# Version: Traipse 'Ornery-Orc'
+#   $Id: main.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This is the main entry point of the oprg application
 #
 
-__version__ = "$Id: main.py,v 1.154 2009/07/19 03:52:03 madmathlabs Exp $"
+__version__ = "$Id: main.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import *
@@ -50,24 +50,19 @@
 import orpg.mapper.images
 
 import orpg.dieroller.utils
-
-#Update Manager# Un remark if you have Mercurial installed
 import upmana.updatemana
-import upmana.manifest as manifest
+from upmana.manifest import manifest
 
 from orpg.dirpath import dir_struct
-#from orpg.dieroller.utils import DiceManager
 from orpg.tools.settings import settings
 from orpg.tools.validate import validate
 from orpg.tools.passtool import PassTool
 from orpg.tools.orpg_log import logger, crash, debug
 from orpg.tools.metamenus import MenuBarEx
+from orpg.tools.InterParse import Parse
 
 from xml.etree.ElementTree import ElementTree, Element, parse
 from xml.etree.ElementTree import fromstring, tostring
-## Element Tree usage will require users to convert to and from string data quite often until users of older versions update.
-## This is a problem that users of older versions will need to cross as it is both Core and Traipse that will make the change.
-## Older versions have a problem with correct XML.
 from orpg.orpg_xml import xml #to be replaced by etree
 
 
@@ -77,7 +72,7 @@
 
 
 class orpgFrame(wx.Frame):
-    
+
     def __init__(self, parent, id, title):
         wx.Frame.__init__(self, parent, id, title, wx.Point(100, 100), wx.Size(600,420), style=wx.DEFAULT_FRAME_STYLE)
         self.validate = component.get("validate")
@@ -299,7 +294,8 @@
         self.mainmenu.Insert(8, self.traipseSuite, "&Traipse Suite!")
         if menuitem == 'debug':
             if self.debugger.IsShown() == True:
-                self.mainmenu.Replace(8, self.traipseSuite, '&Traipse Suite')
+                self.mainmenu.Remove(8)
+                self.mainmenu.Insert(8, self.traipseSuite, "&Traipse Suite")
             else:
                 self.debugConsole.SetBitmap(wx.Bitmap(dir_struct["icon"] + 'spotlight.png'))
                 self.traipseSuite.RemoveItem(self.debugConsole)
@@ -374,18 +370,15 @@
             if textColor != None: wnd.SetNonActiveTabTextColour(textColor)
             wnd.Refresh()
 
-    
     def OnMB_OpenRPGNewMap(self):
         pass #Not Implemented yet!
 
-    
     def OnMB_OpenRPGTabStylesSlantedColorful(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedColorful"):
             settings.change('TabTheme', 'slanted&colorful')
             self.SetTabStyles("OpenRPGTabStylesSlantedColorful", FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS)
         else: self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedColorful", True)
 
-    
     def OnMB_OpenRPGTabStylesSlantedBlackandWhite(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedBlackandWhite"):
             settings.change('TabTheme', 'slanted&bw')
@@ -393,7 +386,6 @@
                 FNB.FNB_VC8, graidentTo=wx.WHITE, graidentFrom=wx.WHITE, textColor=wx.BLACK)
         else: self.mainmenu.SetMenuState("OpenRPGTabStylesSlantedBlackandWhite", True)
 
-    
     def OnMB_OpenRPGTabStylesSlantedAqua(self):
         if self.mainmenu.GetMenuState("OpenRPGTabStylesSlantedAqua"):
             settings.change('TabTheme', 'slanted&aqua')
@@ -505,7 +497,7 @@
         else: self.updateMana.Show()
 
     def OnMB_DebugConsole(self, evt):
-        self.TraipseSuiteWarnCleanup('debug') ### Beta ###
+        self.TraipseSuiteWarnCleanup('debug')
         if self.debugger.IsShown() == True: self.debugger.Hide()
         else: self.debugger.Show()
 
@@ -514,28 +506,28 @@
         if self.mainmenu.GetMenuState("ToolsLoggingLevelDebug"): lvl |= ORPG_DEBUG
         else: lvl &= ~ORPG_DEBUG
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelNote(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelNote"): lvl |= ORPG_DEBUG
         else: lvl &= ~ORPG_DEBUG
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelInfo(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelInfo"): lvl |= ORPG_INFO
         else: lvl &= ~ORPG_INFO
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsLoggingLevelGeneral(self):
         lvl = logger.log_level
         if self.mainmenu.GetMenuState("ToolsLoggingLevelGeneral"): lvl |= ORPG_GENERAL
         else: lvl &= ~ORPG_GENERAL
         logger.log_level = lvl
-        settings.set('LoggingLevel', lvl)
+        settings.change('LoggingLevel', lvl)
 
     def OnMB_ToolsPasswordManager(self):
         if self.mainmenu.GetMenuState("ToolsPasswordManager"): self.password_manager.Enable()
@@ -631,9 +623,7 @@
         #self.manifest = manifest.ManifestChanges()
         self.updateMana = upmana.updatemana.updaterFrame(self, 
             "OpenRPG Update Manager 1.0", component, manifest, True)
-        print component.get('upmana-win')
         component.add('upmana-win', self.updateMana)
-        print component.get('upmana-win')
         logger.debug("Menu Created")
         h = int(xml_dom.get("height"))
         w = int(xml_dom.get("width"))
@@ -685,7 +675,7 @@
         logger.debug("Status Window Created")
 
         # Create and show the floating dice toolbar
-        self.dieToolBar = orpg.tools.toolBars.DiceToolBar(self, callBack = self.chat.ParsePost)
+        self.dieToolBar = orpg.tools.toolBars.DiceToolBar(self, callBack = Parse.Post)
         wndinfo = AUI.AuiPaneInfo()
         menuid = wx.NewId()
         self.mainwindows[menuid] = "Dice Tool Bar"
@@ -950,7 +940,6 @@
                     wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                 if dlg.ShowModal() == wx.ID_YES:
                   dlg.Destroy()
-                  debug(child)
                   self.tree.on_receive_data(tostring(child))
                   self.chat.InfoPost(display_name + " has sent you a tree node...")
             elif child.tag == 'map':
@@ -1112,7 +1101,8 @@
 		'Bernhard Bergbauer', 'Chris Blocher', 'David Byron', 'Ben Collins-Sussman', 'Robin Cook', 'Greg Copeland',
 		'Chris Davis', 'Michael Edwards', 'Andrew Ettinger', 'Todd Faris', 'Dj Gilcrease',
         'Christopher Hickman', 'Paul Hosking', 'Brian Manning', 'Scott Mackay', 'Jesse McConnell', 
-		'Brian Osman', 'Rome Reginelli', 'Christopher Rouse', 'Dave Sanders', 'Tyler Starke', 'Mark Tarrabain']
+		'Brian Osman', 'Rome Reginelli', 'Christopher Rouse', 'Dave Sanders', 'Tyler Starke', 'Mark Tarrabain',
+        'David Vrabel']
         for dev in orpg_devs:
             self.About.AppendText(dev+'\n')
 
--- a/orpg/mapper/background.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: background.py,v 1.29 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: background.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: background.py,v 1.29 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: background.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 import thread, urllib, os.path, time, mimetypes
--- a/orpg/mapper/background_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: background_handler.py,v 1.23 2007/03/09 14:17:15 digitalxero Exp $
+#   $Id: background_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Background layer handler
 #
-__version__ = "$Id: background_handler.py,v 1.23 2007/03/09 14:17:15 digitalxero Exp $"
+__version__ = "$Id: background_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import thread, mimetypes, os
 from threading import Lock
--- a/orpg/mapper/background_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/background_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: background_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: background_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: background_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: background_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
--- a/orpg/mapper/base.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: base.py,v 1.18 2007/02/12 02:29:08 digitalxero Exp $
+#   $Id: base.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: base.py,v 1.18 2007/02/12 02:29:08 digitalxero Exp $"
+__version__ = "$Id: base.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from images import ImageHandler
 from orpg.tools.rgbhex import *
--- a/orpg/mapper/base_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: base_handler.py,v 1.20 2007/11/04 17:32:25 digitalxero Exp $
+#   $Id: base_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: base layer handler.
 #   layer handlers are responsible for the GUI elements of the layer
 #
-__version__ = "$Id: base_handler.py,v 1.20 2007/11/04 17:32:25 digitalxero Exp $"
+__version__ = "$Id: base_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 from orpg.orpg_windows import *
@@ -42,14 +42,12 @@
         self.chat = component.get("chat")
         self.build_ctrls()
         self.build_menu()
-        #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_LEFT_DCLICK, self.on_left_dclick)
 
     def build_ctrls(self):
         self.basesizer = wx.BoxSizer(wx.HORIZONTAL)
         self.sizer = wx.BoxSizer(wx.HORIZONTAL)
         self.buttonsizer = wx.BoxSizer(wx.HORIZONTAL)
-
         self.zoom_in_button = createMaskedButton( self, 
             dir_struct["icon"]+'zoom_in.gif', "Zoom in from x1.0", wx.ID_ANY )
         self.zoom_out_button = createMaskedButton( self, 
--- a/orpg/mapper/base_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/base_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: base_msg.py,v 1.9 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: base_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: base_msg.py,v 1.9 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: base_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from threading import RLock
 from orpg.networking.mplay_client import *
@@ -38,7 +38,6 @@
 
         if not hasattr(self,"tagname"):
             raise Exception, "This is a virtual class that cannot be directly instantiated.  Set self.tagname in derived class."
-
         self._props = {}
         #  This is a dictionary that holds (value,changed) 2-tuples, indexed by attribute
         #  Avoid manipulating these values directly.  Instead, use the provided accessor methods.
--- a/orpg/mapper/fog_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/fog_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,9 +21,9 @@
 # Author: Mark Tarrabain
 # Maintainer:
 # Version:
-#   $Id: fog_msg.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: fog_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-__version__ = "$Id: fog_msg.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: fog_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 from region import *
--- a/orpg/mapper/grid.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid.py,v 1.29 2007/12/07 20:39:49 digitalxero Exp $
+#   $Id: grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: grid.py,v 1.29 2007/12/07 20:39:49 digitalxero Exp $"
+__version__ = "$Id: grid.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 from isometric import *
--- a/orpg/mapper/grid_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -20,11 +20,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid_handler.py,v 1.20 2007/04/03 00:14:35 digitalxero Exp $
+#   $Id: grid_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: grid layer handler
 #
-__version__ = "$Id: grid_handler.py,v 1.20 2007/04/03 00:14:35 digitalxero Exp $"
+__version__ = "$Id: grid_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from grid import *
 from base_handler import *
--- a/orpg/mapper/grid_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/grid_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: grid_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: grid_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: grid_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: grid_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import map_element_msg_base
 #from base_msg import * ## ?? import all? Deprecated!?
--- a/orpg/mapper/images.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/images.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $
+#   $Id: images.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
--- a/orpg/mapper/map.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $
+#   $Id: map.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $"
+__version__ = "$Id: map.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from map_version import MAP_VERSION
 from map_msg import *
@@ -367,8 +367,6 @@
             dc.SetUserScale(self.layers['grid'].mapscale,self.layers['grid'].mapscale)
             # Grab the current map position
             pos = self.snapMarker( evt.GetLogicalPosition( dc ) )
-            # Enable brush optimizations
-            # dc.SetOptimization( True )
             # Set up the pen used for drawing our marker
             dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) )
             # Now, based on the marker mode, draw the right thing
@@ -386,8 +384,6 @@
                 # As long as we are in marker mode, we ned to update the stop point
                 self.markerStop = pos
             dc.SetPen(wx.NullPen)
-            # Disable brush optimizations
-            #dc.SetOptimization( False )
             del dc
 
     def on_tape_down(self, evt):
@@ -403,8 +399,6 @@
         self.markerMode = MARKER_MODE_MEASURE
         # Erase the old line if her have one
         if self.markerStart.x != -1 and self.markerStart.y != -1:
-            # Enable brush optimizations
-            #dc.SetOptimization( True )
             # Set up the pen used for drawing our marker
             dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) )
             # Set the DC function that we need
@@ -416,8 +410,6 @@
             # Restore the default DC function and pen
             dc.SetLogicalFunction(wx.COPY)
             dc.SetPen(wx.NullPen)
-            # Disable brush optimizations
-            #dc.SetOptimization( False )
         # Save our current start and reset the stop value
         self.markerStart = pos
         self.markerStop = pos
--- a/orpg/mapper/map_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -20,11 +20,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: map_handler.py,v 1.14 2007/04/03 00:14:35 digitalxero Exp $
+#   $Id: map_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: map layer handler
 #
-__version__ = "$Id: map_handler.py,v 1.14 2007/04/03 00:14:35 digitalxero Exp $"
+__version__ = "$Id: map_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 
--- a/orpg/mapper/map_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,13 +21,12 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map_msg.py,v 1.16 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: map_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map_msg.py,v 1.16 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: map_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-#from base import *
 from base_msg import *
 from background_msg import *
 from grid_msg import *
--- a/orpg/mapper/map_prop_dialog.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/map_prop_dialog.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG
 # Maintainer:
 # Version:
-#   $Id: map_prop_dialog.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: map_prop_dialog.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description:
 #
-__version__ = "$Id: map_prop_dialog.py,v 1.16 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: map_prop_dialog.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_windows import *
 from background import *
--- a/orpg/mapper/min_dialogs.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/min_dialogs.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: min_dialogs.py,v 1.27 2006/11/13 02:23:16 digitalxero Exp $
+#   $Id: min_dialogs.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
@@ -146,10 +146,8 @@
              #############
                 min_xml = sel_rmin.toxml(action="new")
                 node_begin = "<nodehandler module='map_miniature_nodehandler' class='map_miniature_handler' name='"
-
                 if sel_rmin.label: node_begin += sel_rmin.label + "'"
                 else: node_begin += "Unnamed Miniature'"
-
                 node_begin += ">"
                 gametree = component.get('tree')
                 node_xml = node_begin + min_xml + '</nodehandler>'
@@ -308,14 +306,11 @@
         positionbox.Add(poschoicebox,0,0)
         listsizer.Add(positionbox,0, 0)
         self.listsizer = listsizer
-        #self.outline = wx.StaticBox(self,-1,"Miniature list properties")
-        #listsizer.Add(self.outline,0, wx.EXPAND)
         self.SetSizer(listsizer)
         self.SetAutoLayout(True)
         self.Fit()
         self.Bind(wx.EVT_SPINCTRL, self.on_spin, id=POS_SPIN)
         self.Bind(wx.EVT_TEXT, self.on_combo_box, id=POS_COMB)
-        #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
         self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
         self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
@@ -500,12 +495,10 @@
 
 class min_edit_dialog(wx.Dialog):
     def __init__(self,parent,min):
-        #520,265
         wx.Dialog.__init__(self,parent,-1,"Miniature",wx.DefaultPosition,wx.Size(520,350))
         (w,h) = self.GetClientSizeTuple()
         mastersizer = wx.BoxSizer(wx.VERTICAL)
         editor = min_edit_panel(self,min)
-        #editor.SetDimensions(0,0,w,h-25)
         self.editor = editor
         mastersizer.Add(editor, 1, wx.EXPAND)
         mastersizer.Add(wx.Size(10,10))
@@ -513,7 +506,6 @@
         sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
         sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        #sizer.SetDimension(0,h-25,w,25)
         mastersizer.Add(sizer, 0, wx.EXPAND)
         self.SetSizer(mastersizer)
         self.SetAutoLayout(True)
@@ -523,3 +515,4 @@
     def on_ok(self,evt):
         self.editor.update_min()
         self.EndModal(wx.ID_OK)
+
--- a/orpg/mapper/miniatures.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
+#   $Id: miniatures.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
+__version__ = "$Id: miniatures.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 import thread, time, urllib, os.path, mimetypes
@@ -196,7 +196,6 @@
             self.right = self.bmp.GetWidth()
             self.top = 0
             self.bottom = self.bmp.GetHeight()
-        
             # Draw the facing marker if needed
             if self.face != 0:
                 x_mid = self.pos.x + (self.bmp.GetWidth()/2)
@@ -206,7 +205,6 @@
                 dc.SetPen(wx.WHITE_PEN)
                 dc.SetBrush(wx.RED_BRUSH)
                 triangle = []
-        
                 # Figure out which direction to draw the marker!!
                 tri_list = {
                 FACE_WEST: [cmpPoint(self.pos.x, self.pos.y), cmpPoint(self.pos.x-5, y_mid), cmpPoint(self.pos.x, y_bottom)], 
@@ -225,7 +223,6 @@
                 dc.DrawPolygon(triangle)
                 dc.SetBrush(wx.NullBrush)
                 dc.SetPen(wx.NullPen)
-        
             # Draw the heading if needed
             if self.heading:
                 x_adjust = 0
@@ -343,7 +340,7 @@
         xml_str += " />"
         if (action == "update" and self.isUpdated) or action == "new":
             self.isUpdated = False
-            print xml_str; return xml_str
+            return xml_str
         else: return ''
 
     def takedom(self, xml_dom):
@@ -376,7 +373,7 @@
     def __init__(self, canvas):
         self.canvas = canvas
         layer_base.__init__(self)
-        self.id = -1 #added.
+        self.id = -1 
         self.miniatures = []
         self.serial_number = 0
         self.show_labels = True
--- a/orpg/mapper/miniatures_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: miniatures_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $
+#   $Id: miniatures_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Miniature layer handler
 #
-__version__ = "$Id: miniatures_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $"
+__version__ = "$Id: miniatures_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 from min_dialogs import *
@@ -36,7 +36,6 @@
 from grid import GRID_ISOMETRIC
 
 from orpg.tools.orpg_settings import settings
-
 from xml.etree.ElementTree import ElementTree, Element
 from xml.etree.ElementTree import fromstring, tostring
 
@@ -118,7 +117,6 @@
         dt = myFileDropTarget(self)
         self.canvas.SetDropTarget(dt)
         self.tooltip = wx.ToolTip('')
-        #wxInitAllImageHandlers()
 
     def build_ctrls(self):
         base_layer_handler.build_ctrls(self)
--- a/orpg/mapper/miniatures_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/miniatures_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: miniatures_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: miniatures_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: miniatures_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: miniatures_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
--- a/orpg/mapper/region.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/region.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,9 +21,9 @@
 # Author: Mark Tarrabain
 # Maintainer:
 # Version:
-#   $Id: region.py,v 1.10 2006/11/04 21:24:21 digitalxero Exp $
+#   $Id: region.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
-__version__ = "$Id: region.py,v 1.10 2006/11/04 21:24:21 digitalxero Exp $"
+__version__ = "$Id: region.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import sys
 
--- a/orpg/mapper/whiteboard.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: whiteboard.py,v 1.47 2007/03/09 14:11:55 digitalxero Exp $
+#   $Id: whiteboard.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: whiteboard.py,v 1.47 2007/03/09 14:11:55 digitalxero Exp $"
+__version__ = "$Id: whiteboard.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base import *
 from orpg.mapper.map_utils import *
--- a/orpg/mapper/whiteboard_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard_handler.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,11 +21,11 @@
 # Author: OpenRPG Team
 # Maintainer:
 # Version:
-#   $Id: whiteboard_handler.py,v 1.37 2007/03/09 14:11:56 digitalxero Exp $
+#   $Id: whiteboard_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Whiteboard layer handler
 #
-__version__ = "$Id: whiteboard_handler.py,v 1.37 2007/03/09 14:11:56 digitalxero Exp $"
+__version__ = "$Id: whiteboard_handler.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_handler import *
 from math import floor, sqrt
--- a/orpg/mapper/whiteboard_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/mapper/whiteboard_msg.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: whiteboard_msg.py,v 1.12 2007/03/09 14:11:56 digitalxero Exp $
+#   $Id: whiteboard_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains some of the basic definitions for the chat
 # utilities in the orpg project.
 #
-__version__ = "$Id: whiteboard_msg.py,v 1.12 2007/03/09 14:11:56 digitalxero Exp $"
+__version__ = "$Id: whiteboard_msg.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from base_msg import *
 
--- a/orpg/networking/gsclient.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/gsclient.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,13 +21,13 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: gsclient.py,v 1.53 2007/10/25 21:49:34 digitalxero Exp $
+#   $Id: gsclient.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: The file contains code for the game server browser
 #
 
 from __future__ import with_statement
-__version__ = "$Id: gsclient.py,v 1.53 2007/10/25 21:49:34 digitalxero Exp $"
+__version__ = "$Id: gsclient.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 import meta_server_lib
 import orpg.tools.rgbhex
@@ -269,7 +269,6 @@
         address = self.svrList[item].addy
         port = self.svrList[item].port
         self.server_list.SetItemImage(item, 1)
-
         for server in self.bookmarks.findall('server'):
             if server.get('name') == name:
                 self.bookmarks_menu.Remove(
@@ -298,8 +297,8 @@
         except: pass
         address = self.texts["address"].GetValue()
         if self.session.is_connected():
-            if self.session.host_server == address : return #currently connected to address. Do nothing.
-            else: self.frame.kill_mplay_session() #address differs, disconnect.
+            if self.session.host_server == address : return 
+            else: self.frame.kill_mplay_session()
         self.do_connect(address)
 
     def on_room_dbclick(self, evt=None):
@@ -307,13 +306,11 @@
         try: self.on_select(evt)
         except: pass
         group_id = str(self.room_list.GetItemData(self.cur_room_index))
-
         if self.NoGroups:
             self.NoGroups = False
             self.session.group_id = group_id
             self.on_server_dbclick()
             return
-
         if self.cur_room_index >= 0:
             if self.cur_room_index != 0: self.set_lobbybutton(1);
             else: self.set_lobbybutton(0);
@@ -345,7 +342,6 @@
     def on_text(self, evt):
         id = evt.GetId()
         if (id == self.texts["address"].GetValue()) and (self.cur_server_index >= 0):
-            #print "ADDRESS id = ", id, "index = ", self.cur_server_index
             self.cur_server_index = -1
         evt.Skip()
 
@@ -526,17 +522,13 @@
                 self.texts["address"].SetValue("127.0.0.1:6774")
                 self.serverNameSet = 1
             else: pass
-            #  Allow xml_dom to be collected
         except Exception, e:
             print "Server List not available."
             traceback.print_exc()
-
-                
+            
     def failed_connection(self):
         if(self.cur_server_index >= 0):
             server_index = self.servers[self.cur_server_index]
-            #  post_failed_connection will return a non-zero if the server
-            #  was removed.  If it was, refresh the display
             if(meta_server_lib.post_failed_connection(server_index.get('id'), 
                 meta=server_index.get('meta'), address=server_index.get('address'),
                 port=server_index.get('port'))):
@@ -613,11 +605,9 @@
             msg = "%s is creating room \'%s.\'" % (self.session.name, name)
             self.session.send(msg)
             self.session.send_create_group(name, pwd, boot_pwd, minversion)
-            self.set_lobbybutton(1); #enable the Lobby quickbutton
+            self.set_lobbybutton(1); 
 
     def on_size(self, evt):
-        # set column widths for room list
-        # set column widths for server list
         pass
 
     def colorize_group_list(self, groups):
--- a/orpg/networking/meta_server_lib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/meta_server_lib.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,7 +22,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $
+#   $Id: meta_server_lib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: A collection of functions to communicate with the meta server.
 #
@@ -39,7 +39,6 @@
 from orpg.dirpath import dir_struct
 
 import urllib, time, sys, traceback, re
-#import orpg.minidom
 
 from threading import *
 from random import uniform
@@ -47,7 +46,6 @@
 from orpg.tools.orpg_log import debug
 
 from xml.etree.ElementTree import Element, fromstring
-
 metacache_lock = RLock()
 
 def get_server_dom(data=None,path=None, string=False):
@@ -314,7 +312,7 @@
 
 def getMetaServerBaseURL():
     # get meta server URL
-    url = "http://www.openrpg.com/openrpg_servers.php"
+    url = "http://orpgmeta.appspot.com/"
     try:
         component.get('validate').config_file("settings.xml","default_settings.xml")
         ini = open(dir_struct["user"]+"settings.xml","r")
@@ -325,6 +323,7 @@
         node_list = tree.getElementsByTagName("MetaServerBaseURL")
         if node_list:
             url = node_list[0].getAttribute("value")
+        print url
         # allow tree to be collected
         try: tree.unlink()
         except: pass
--- a/orpg/networking/mplay_client.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_client.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,16 +21,14 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: mplay_client.py,v 1.71 2007/05/12 20:41:54 digitalxero Exp $
+#   $Id: mplay_client.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the client stubs of the multiplayer
 # features in the orpg project.
 #
 
-__version__ = "$Id: mplay_client.py,v 1.71 2007/05/12 20:41:54 digitalxero Exp $"
+__version__ = "$Id: mplay_client.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-### Alpha ### 
-##import orpg.minidom ## Deprecated. xml.parseXml calls minidom.parseString so it was superfluous and wasteful.
 import socket, Queue, thread, traceback, errno, os, time
 
 from threading import Event, Lock
@@ -123,7 +121,7 @@
         self.ROLE_LURKER = "Lurker"
         ## --TaS
         try: self.ip = socket.gethostbyname(socket.gethostname())
-	except: self.ip = socket.gethostbyname('localhost')
+        except: self.ip = socket.gethostbyname('localhost')
         self.remote_ip = None
         self.version = VERSION
         self.protocol_version = PROTOCOL_VERSION
@@ -625,7 +623,6 @@
         el.set('from', self.id)
         el.set('pwd', pwd)
         el.set('group_id', str(group_id))
-
         self.outbox.put(tostring(el))
 
     def poll(self, evt=None):
@@ -766,7 +763,6 @@
             self.on_player_event(mplay_event(PLAYER_DEL, self.players[id]))
             if self.players.has_key(id): del self.players[id]
             if id == self.id: self.do_disconnect()
-        #  the next two cases handle the events that are used to let you know when others are typing
         elif act == "update":
             if id == self.id:
                 self.players[id] = player
@@ -842,7 +838,7 @@
         outgoing = self.toxml('del')
         if iselement(outgoing): outgoing = tostring(outgoing)
         self.outbox.put(outgoing)
-        ## Client Side Disconect Forced -- Snowdog 10-09-2003
+        ## Client Side Disconnect Forced -- Snowdog 10-09-2003
         #pause to allow GUI events time to sync.
         time.sleep(1)
         self.do_disconnect()
@@ -862,3 +858,4 @@
         self.unique_cookie += 1
         return_str = self.id + "-" + str(self.unique_cookie)
         return return_str
+
--- a/orpg/networking/mplay_messaging.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_messaging.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,24 +21,20 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: mplay_messaging.py,v 1.5 2007/05/06 16:42:59 digitalxero Exp $
+#   $Id: mplay_messaging.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the client / server messaging
 #
 
-__version__ = "$Id: mplay_messaging.py,v 1.5 2007/05/06 16:42:59 digitalxero Exp $"
+__version__ = "$Id: mplay_messaging.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
-import socket
-import Queue
-import thread
-import traceback
+import socket, Queue, thread, traceback, os, time
+
 from threading import Event, Lock
 from xml.sax.saxutils import escape
 from struct import pack, unpack, calcsize
 from string import *
 from orpg.orpg_version import VERSION, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
-import os
-import time
 
 from orpg.tools.orpg_log import logger
 from orpg.orpgCore import component
@@ -91,20 +87,6 @@
         self.players = {}
         self.groups = {}
 
-        #Setup Stuff from the Server
-        """
-        if kwargs.has_key('inbox'): self.inbox = kwargs['inbox']
-        if kwargs.has_key('sock'): self.sock = kwargs['sock']
-        if kwargs.has_key('ip'): self.ip = kwargs['ip']
-        if kwargs.has_key('role'): self.role = kwargs['role']
-        if kwargs.has_key('id'): self.id = kwargs['id']
-        if kwargs.has_key('group_id'): self.group_id = kwargs['group_id']
-        if kwargs.has_key('name'): self.name = kwargs['name']
-        if kwargs.has_key('version'): self.version = kwargs['version']
-        if kwargs.has_key('protocol_version'): self.protocol_version = kwargs['protocol_version']
-        if kwargs.has_key('client_string'): self.client_string = kwargs['client_string']
-        """
-
         ### Alpha ###
         self.inbox = kwargs['inbox'] or pass
         self.sock = kwargs['sock'] or pass
@@ -207,7 +189,6 @@
     def __str__(self):
         return "%s(%s)\nIP:%s\ngroup_id:%s\n%s (%s)" % (self.name, self.id, self.ip, self.group_id, self.idle_time(), self.connected_time())
 
-    # idle time functions added by snowdog 3/31/04
     def update_idle_time(self):
         self.lastmessagetime = time.time()
 
@@ -326,7 +307,6 @@
         #Message Action thread expires and closes here.
         return
 
-    #Privet functions
     def sendThread( self, arg ):
         "Sending thread.  This thread reads from the data queue and writes to the socket."
         # Wait to be told it's okay to start running
@@ -352,11 +332,7 @@
     def sendMsg( self, sock, msg ):
         """Very simple function that will properly encode and send a message to te
         remote on the specified socket."""
-
-        # Calculate our message length
         length = len( msg )
-
-        # Encode the message length into network byte order
         lp = pack( 'i', socket.htonl( length ) )
 
         try:
@@ -434,13 +410,11 @@
         msgData = ""
         try:
             lenData = self.recvData( sock, self.lensize )
-
             # Now, convert to a usable form
             (length,) = unpack( 'i', lenData )
             length = socket.ntohl( length )
             # Read exactly the remaining amount of data
             msgData = self.recvData( sock, length )
-
             if self.isServer: logger.debug("('data_recv', " + str(length+4) + ")")
         except: logger.exception("Exception: messenger->recvMsg():\n" + traceback.format_exc())
         return msgData
@@ -448,3 +422,4 @@
 if __name__ == "__main__":
     test = messenger(None)
     print test.build_message('hello', "This is a test message", attrib1="hello world", attrib2="hello world2", attrib3="hello world3")
+
--- a/orpg/networking/mplay_server.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_server.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,7 +22,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: mplay_server.py,v 1.155 2008/01/24 03:52:03 digitalxero Exp $
+#   $Id: mplay_server.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This file contains the code for the server of the multiplayer
 # features in the orpg project.
@@ -33,7 +33,7 @@
 
 from __future__ import with_statement
 
-__version__ = "$Id: mplay_server.py,v 1.155 2008/01/24 03:52:03 digitalxero Exp $"
+__version__ = "$Id: mplay_server.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 #!/usr/bin/env python
 """
@@ -64,7 +64,7 @@
 from orpg.tools.decorators import debugging
 
 # Snag the version number
-from orpg.orpg_version import VERSION, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
+from orpg.orpg_version import VERSION, DISTRO, DIS_VER, BUILD, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION
 
 #Plugins
 from server_plugins import ServerPlugins
@@ -253,7 +253,7 @@
         self.allowRemoteKill = False
         self.allowRemoteAdmin = True
         self.sendLobbySound = False
-        self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu' ##used?
+        #self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu' ##used?
 
     def initServer(self, **kwargs):
         for atter, value in kwargs.iteritems(): setattr(self, atter, value)
@@ -1069,7 +1069,7 @@
             msg = self.groups[group_id].game_map.get_all_xml()
             self.send(msg,id,group_id)
 
-    def new_request(self,newsock, xml_dom, LOBBY_ID='0'):
+    def new_request(self, newsock, xml_dom, LOBBY_ID='0'):
         #build client stub
         props = {}
         # Don't trust what the client tells us...trust what they connected as!
@@ -1101,14 +1101,15 @@
 
         # send confirmation
         data = self.recvMsg(newsock, new_stub.useCompression, new_stub.compressionType)
-        try: xml_dom = XML(data)
+        try: 
+            xml_dom = XML(data)
         except Exception, e:
             print e
             (remote_host,remote_port) = newsock.getpeername()
             bad_xml_string =  "Your client sent an illegal message to the server and will be disconnected. "
             bad_xml_string += "Please report this bug to the development team at:<br /> "
-            bad_xml_string += "<a href=\"http://sourceforge.net/tracker/?group_id=2237&atid=102237\">OpenRPG bugs "
-            bad_xml_string += "(http://sourceforge.net/tracker/?group_id=2237&atid=102237)</a><br />"
+            bad_xml_string += "<a href='http://www.assembla.com/spaces/traipse_dev/tickets/'>Traipse-Dev "
+            bad_xml_string += "(http://www.assembla.com/spaces/traipse_dev/tickets/)</a><br />"
             self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='" + props['id'] + "' group_id='0' />" + bad_xml_string, 
                             new_stub.useCompression, new_stub.compressionType)
 
@@ -1214,7 +1215,8 @@
             newsock.close()
 
         #  Display the lobby message
-        self.SendLobbyMessage(newsock,props['id'])
+        print 'lobby message'
+        self.SendLobbyMessage(newsock, props['id'])
 
     def checkClientVersion(self, clientversion):
         minv = self.minClientVersion.split('.')
@@ -1234,8 +1236,9 @@
         #  prepend this server's version string to the the lobby message
         """
         try:
-            lobbyMsg = "You have connected to an <a href=\"http://www.openrpg.com\">OpenRPG</a> "
-            lobbyMsg += "server, version '" + VERSION + "'"
+            lobbyMsg = "You have connected to a <a href='http://www.knowledgearcana.com//content/view/199/128/'>"
+            lobbyMsg += DISTRO +'</a> '+ DIS_VER +' {'+ BUILD+'}'
+            lobbyMsg += " server, built on OpenRPG version '" + VERSION + "'"
 
             # See if we have a server name to report!
             if len(self.serverName): lobbyMsg += ", named '" + self.serverName + "'."
@@ -1250,7 +1253,6 @@
                 open_msg = open( self.userPath + "LobbyMessage.html", "r" )
                 lobbyMsg += open_msg.read()
                 open_msg.close()
-
             # Send the server's lobby message to the client no matter what
             self.sendMsg(socket, "<msg to='" + player_id + "' from='0' group_id='0' />" + lobbyMsg, 
                         self.players[player_id].useCompression, self.players[player_id].compressionType)
@@ -1603,6 +1605,7 @@
             #notify user about others in the room
             self.return_room_roles(from_id,group_id)
             self.log_msg(("join_group", (self.groups[group_id].name, group_id, from_id)))
+            self.log_msg(("update_group", (self.groups[old_group_id].name, old_group_id, len(self.groups[old_group_id].players) )))
             self.log_msg(("update_group", (self.groups[group_id].name, group_id, len(self.groups[group_id].players) )))
             self.handle_role("set", from_id, self.players[from_id].role, self.groups[group_id].boot_pwd, group_id)
         except Exception, e:
@@ -1632,7 +1635,7 @@
         if persist !=0: ins="Persistant "
         lmsg = "Creating " + ins + "Group... (" + str(group_id) + ") " + str(name)
         self.log_msg( lmsg )
-        self.log_msg(("create_group", (str(name), int(group_id), pwd, 0) ))
+        self.log_msg(("create_group", (str(name), int(group_id), 0, 'No' if pwd == '' else 'Yes') ))
 
     def change_group_name(self, gid, name, pid):
         "Change the name of a group"
@@ -2145,7 +2148,6 @@
         except: pass
 
     def send(self,msg,player,group):
-        debug(msg)
         self.players[player].send(msg,player,group)
 
     def send_to_all(self,from_id,data):
@@ -2162,7 +2164,6 @@
     def send_to_group(self, from_id, group_id, data):
         #data = ("<msg to='all' from='0' group_id='"+str(group_id)+"' /><font color='#FF0000'>" + data + "</font>")
         data = ServerPlugins.postParseIncoming(data) #Function breaks here.
-        debug(data)
         try:
             self.p_lock.acquire()
             keys = self.groups[group_id].get_player_ids()
@@ -2186,10 +2187,8 @@
 
     def send_group_list(self, to_id, action="new"):
         try:
-            print self.groups
             for key in self.groups:
                 xml = self.groups[key].toxml(action)
-                print xml, key
                 self.players[to_id].outbox.put(xml)
         except Exception, e:
             self.log_msg("Exception: send_group_list(): (client #"+to_id+") : " + str(e))
--- a/orpg/networking/mplay_server_gui.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/networking/mplay_server_gui.py	Sat Apr 24 08:37:20 2010 -0500
@@ -6,18 +6,16 @@
 
 __appname__=' OpenRPG GUI Server v0.7 '
 __version__='$Revision: 1.26 $'[11:-2]
-__cvsinfo__='$Id: mplay_server_gui.py,v 1.26 2007/11/06 00:32:39 digitalxero Exp $'[5:-2]
+__cvsinfo__="$Id: mplay_server_gui.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"[5:-2]
 __doc__="""OpenRPG Server Graphical Interface"""
 
-import os, sys, time, types
+import os, sys, time, types, webbrowser
 
 from orpg.dirpath import dir_struct
 from orpg.tools.validate import validate
 from orpg.orpg_wx import *
 from threading import Thread
 
-import webbrowser
-
 from meta_server_lib import post_server_data, remove_server
 from mplay_server import mplay_server, server
 
@@ -32,11 +30,7 @@
 # Constants ######################################
 SERVER_RUNNING = 1
 SERVER_STOPPED = 0
-
-### Alpha ###
 MENU_MODIFY_BANLIST = wx.NewId()
-#############
-
 MENU_PLAYER_CREATE_ROOM = wx.NewId()
 
 # Our new event type that gets posted from one
@@ -157,8 +151,8 @@
         (room, room_id, players, passworded) = data
         i = self.InsertStringItem(0, str(room_id))
         self.SetStringItem(i, 1, room)
-        self.SetStringItem(i, 2, players)
-        self.SetStringItem(i, 3, str(passworded))
+        self.SetStringItem(i, 2, str(players))
+        self.SetStringItem(i, 3, passworded)
 
     def DeleteGroup(self, data):
         i = self.FindItem(-1, str(data))
@@ -168,7 +162,7 @@
         (room, room_id, players) = data
         i = self.FindItem( -1, str(room_id))
         self.SetStringItem( i, 1, room )
-        if players: self.SetStringItem(i, 2, str(players))
+        self.SetStringItem(i, 2, str(players))
         ### Need to add room for Password Updates ###
 
 class Connections(wx.ListCtrl):
@@ -268,7 +262,6 @@
             self.SetItem(item)
 
     def update(self, player):
-        #try: int(player); i = self.FindItemData( -1, int(player) )
         i = self.FindItemData( -1, int(player["id"]) )
         if i > -1:
             self.SetStringItem(i, 1, self.stripHtml(player["name"]))
@@ -361,8 +354,8 @@
     STATUS = SERVER_STOPPED
     def __init__(self, parent, id, title):
         wx.Frame.__init__(self, parent, id, title, size = (760, 560) )
-        if wx.Platform == '__WXMSW__': icon = wx.Icon( dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO )
-        else: icon = wx.Icon( dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF )
+        if wx.Platform == '__WXMSW__': icon = wx.Icon(dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO)
+        else: icon = wx.Icon(dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF)
         self.SetIcon(icon)
         self.serverName = "Server Name"
         self.bootPwd = ""
@@ -408,10 +401,10 @@
 
         # File Menu
         menu = wx.Menu()
-        menu.Append( 1, 'Start', 'Start server.')
-        menu.Append( 2, 'Stop', 'Shutdown server.')
+        menu.Append(1, 'Start', 'Start server.')
+        menu.Append(2, 'Stop', 'Shutdown server.')
         menu.AppendSeparator()
-        menu.Append( 3, 'E&xit', 'Exit application.')
+        menu.Append(3, 'E&xit', 'Exit application.')
         self.Bind(wx.EVT_MENU, self.OnStart, id=1)
         self.Bind(wx.EVT_MENU, self.OnStop, id=2)
         self.Bind(wx.EVT_MENU, self.OnExit, id=3)
@@ -419,23 +412,24 @@
 
         # Registration Menu
         menu = wx.Menu()
-        menu.Append( 4, 'Register', 'Register with OpenRPG server directory.')
-        menu.Append( 5, 'Unregister', 'Unregister from OpenRPG server directory.')
+        menu.Append(4, 'Register', 'Register with OpenRPG server directory.')
+        menu.Append(5, 'Unregister', 'Unregister from OpenRPG server directory.')
         self.Bind(wx.EVT_MENU, self.OnRegister, id=4)
         self.Bind(wx.EVT_MENU, self.OnUnregister, id=5)
         self.mainMenu.Append( menu, '&Registration' )
 
         # Server Configuration Menu
         menu = wx.Menu()
-        menu.Append( 6, 'Ban List', 'Modify Ban List.')
+        menu.Append(6, 'Ban List', 'Modify Ban List.')
         menu.Append(11, 'Zombies', 'Set auto-kick time for zombie clients')
         menu.Append(14, 'Send Size', 'Adjust the send size limit')
         menu.AppendSeparator()
-        menu.Append( 7, 'Start Ping', 'Ping players to validate remote connection.' )
-        menu.Append( 8, 'Stop Ping', 'Stop validating player connections.' )
-        menu.Append( 9, 'Ping Interval', 'Change the ping interval.' )
+        menu.Append(7, 'Start Ping', 'Ping players to validate remote connection.' )
+        menu.Append(8, 'Stop Ping', 'Stop validating player connections.' )
+        menu.Append(9, 'Ping Interval', 'Change the ping interval.' )
         menu.AppendSeparator()
-        menu.AppendCheckItem( 10, 'Server Logging', 'Turn on or off the Server GUI Log').Check(self.do_log)
+        menu.AppendCheckItem(10, 'Server Logging', 
+                                'Turn on or off the Server GUI Log').Check(self.do_log)
         menu.AppendCheckItem(12, 'Room Passwords', 'Allow or Deny Room Passwords').Check(False)
         menu.AppendCheckItem(13, 'Remote Admin', 'Allow or Deny Remote Admin').Check(False)
         menu.AppendCheckItem(15, 'Remote Kill', 'Allow or Deny Remote Admin Server Kill').Check(False)
@@ -444,37 +438,38 @@
         self.Bind(wx.EVT_MENU, self.StopPingPlayers, id=8)
         self.Bind(wx.EVT_MENU, self.ConfigPingInterval, id=9)
         self.Bind(wx.EVT_MENU, self.LogToggle, id=10)
-        self.mainMenu.Append( menu, '&Configuration' )
-        self.SetMenuBar( self.mainMenu )
+        self.mainMenu.Append( menu, '&Configuration')
+        self.SetMenuBar(self.mainMenu)
 
-        self.mainMenu.Enable( 2, False )
-        self.mainMenu.Enable( 4, False )
-        self.mainMenu.Enable( 5, False )
+        self.mainMenu.Enable(2, False)
+        self.mainMenu.Enable(4, False)
+        self.mainMenu.Enable(5, False)
 
         # Disable the ping menu items
-        self.mainMenu.Enable( 7, False )
-        self.mainMenu.Enable( 8, False )
-        self.mainMenu.Enable( 9, False )
+        self.mainMenu.Enable(7, False)
+        self.mainMenu.Enable(8, False)
+        self.mainMenu.Enable(9, False)
 
         # Disable placeholders
-        self.mainMenu.Enable( 11, False )
-        self.mainMenu.Enable( 14, False )
-        self.mainMenu.Enable( 12, False )
-        self.mainMenu.Enable( 13, False )
-        self.mainMenu.Enable( 15, False )
+        self.mainMenu.Enable(11, False)
+        self.mainMenu.Enable(14, False)
+        self.mainMenu.Enable(12, False)
+        self.mainMenu.Enable(13, False)
+        self.mainMenu.Enable(15, False)
+
     def build_body(self):
         """ Create the ViewNotebook and logger. """
         splitter = wx.SplitterWindow(self, -1, style=wx.NO_3D | wx.SP_3D)
-        nb = wx.Notebook( splitter, -1 )
+        nb = wx.Notebook(splitter, -1)
         self.conns = Connections(nb, self)
         self.groups = Groups(nb, self)
-        self.msgWindow = HTMLMessageWindow( nb )
+        self.msgWindow = HTMLMessageWindow(nb)
         nb.AddPage(self.conns, "Players")
         nb.AddPage(self.groups, 'Rooms')
-        nb.AddPage( self.msgWindow, "Messages" )
+        nb.AddPage(self.msgWindow, "Messages")
 
         log = wx.TextCtrl(splitter, -1, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
-        wx.Log.SetActiveTarget( wx.LogTextCtrl(log) )
+        wx.Log.SetActiveTarget(wx.LogTextCtrl(log))
         splitter.SplitHorizontally(nb, log, 400)
         splitter.SetMinimumPaneSize(40)
         self.nb = nb
@@ -529,12 +524,14 @@
     def OnDataSent(self, bytes):
         self.total_messages_sent += 1
         self.total_data_sent += bytes
-        self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), self.total_messages_sent), 1)
+        self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), 
+                                self.total_messages_sent), 1)
 
     def OnDataRecv(self, bytes):
         self.total_messages_received += 1
         self.total_data_received += bytes
-        self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), self.total_messages_received), 2)
+        self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), 
+                                self.total_messages_received), 2)
 
     def OnCreateGroup( self, data ):
         (room, room_id, player, pwd) = data
@@ -552,7 +549,7 @@
         self.conns.updateRoom(data)
 
     def OnUpdateGroup(self, data):
-        (room, room_id, players) = data
+        (room, room_id, players) = data; print 'update group', data
         self.groups.UpdateGroup(data)
 
     def OnSetRole( self, data ):
@@ -563,28 +560,29 @@
     def OnStart(self, event = None):
         """ Start server. """
         if self.STATUS == SERVER_STOPPED:
-            # see if we already have name specified 
+            ## Set name and admin password as empty
+            self.serverName = ''
+            self.bootPwd = ''
+            # see if we already have serverName and bootPwd specified
             try:
                 validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
                 configDoc = parse(dir_struct["user"] + 'server_ini.xml').getroot()
-                if configDoc.get("name"): self.serverName = configDoc.get("name")
+                self.serverName = configDoc.get("name")
+                if configDoc.get("admin"): self.bootPwd = configDoc.get("admin") 
+                elif configDoc.get("boot"): self.bootPwd = configDoc.get("boot") 
             except: pass 
             if self.serverName == '':
                 self.serverName = 'Server Name'
-                serverNameEntry = wx.TextEntryDialog(self, "Please Enter The Server Name You Wish To Use:",
-                                                 "Server's Name", self.serverName, wx.OK|wx.CANCEL|wx.CENTRE )
+                serverNameEntry = wx.TextEntryDialog(self, 
+                                    "Please Enter The Server Name You Wish To Use:",
+                                    "Server's Name", 
+                                    self.serverName, wx.OK|wx.CANCEL|wx.CENTRE)
                 if serverNameEntry.ShowModal() == wx.ID_OK: self.serverName = serverNameEntry.GetValue()
-            # see if we already have password specified 
-            try: 
-                validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
-                configDoc = parse(dir_struct["user"] + 'server_ini.xml').getroot()
-                if configDoc.get("admin"): self.bootPwd = configDoc.get("admin") 
-                elif configDoc.get("boot"): self.bootPwd = configDoc.get("boot") 
-            except: pass 
             if self.bootPwd == '': 
                 serverPasswordEntry = wx.TextEntryDialog(self, 
-                                            "Please Enter The Server Admin Password:", "Server's Password", 
-                                            self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE)
+                                    "Please Enter The Server Admin Password:", 
+                                    "Server's Password", 
+                                    self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE)
                 if serverPasswordEntry.ShowModal() == wx.ID_OK: self.bootPwd = serverPasswordEntry.GetValue()
             if len(self.serverName):
                 wx.BeginBusyCursor()
@@ -593,9 +591,9 @@
                 self.STATUS = SERVER_RUNNING
                 self.sb.SetStatusText("Running", 3)
                 self.SetTitle(__appname__ + "- (running) - (unregistered)")
-                self.mainMenu.Enable( 1, False )
-                self.mainMenu.Enable( 2, True )
-                self.mainMenu.Enable( 4, True )
+                self.mainMenu.Enable(1, False)
+                self.mainMenu.Enable(2, True)
+                self.mainMenu.Enable(4, True)
                 wx.EndBusyCursor()
             else: self.show_error("Server is already running.", "Error Starting Server")
 
@@ -607,10 +605,10 @@
             self.STATUS = SERVER_STOPPED
             self.sb.SetStatusText("Stopped", 3)
             self.SetTitle(__appname__ + "- (stopped) - (unregistered)")
-            self.mainMenu.Enable( 1, True )
-            self.mainMenu.Enable( 2, False )
-            self.mainMenu.Enable( 4, False )
-            self.mainMenu.Enable( 5, False )
+            self.mainMenu.Enable(1, True)
+            self.mainMenu.Enable(2, False)
+            self.mainMenu.Enable(4, False)
+            self.mainMenu.Enable(5, False)
             self.conns.DeleteAllItems()
 
     def OnRegister(self, event = None):
@@ -622,8 +620,8 @@
             wx.BeginBusyCursor()
             self.server.server.register(self.serverName)
             self.sb.SetStatusText( ("%s" % (self.serverName)), 4 )
-            self.mainMenu.Enable( 4, False )
-            self.mainMenu.Enable( 5, True )
+            self.mainMenu.Enable(4, False)
+            self.mainMenu.Enable(5, True)
             #self.mainMenu.Enable( 2, False )
             self.SetTitle(__appname__ + "- (running) - (registered)")
             wx.EndBusyCursor()
@@ -636,9 +634,9 @@
         """
         wx.BeginBusyCursor()
         self.server.server.unregister()
-        self.sb.SetStatusText( "Unregistered", 4 )
-        self.mainMenu.Enable( 5, False )
-        self.mainMenu.Enable( 4, True )
+        self.sb.SetStatusText("Unregistered", 4)
+        self.mainMenu.Enable(5, False)
+        self.mainMenu.Enable(4, True)
         #self.mainMenu.Enable( 2, True )
         self.SetTitle(__appname__ + "- (running) - (unregistered)")
         wx.EndBusyCursor()
--- a/orpg/orpg_version.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_version.py	Sat Apr 24 08:37:20 2010 -0500
@@ -4,7 +4,7 @@
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
 DISTRO = "Traipse Alpha"
 DIS_VER = "Ornery Orc"
-BUILD = "100115-02"
+BUILD = "100424-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/orpg_windows.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_windows.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $
+#   $Id: orpg_windows.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: orpg custom windows
 #
 
-__version__ = "$Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $"
+__version__ = "$Id: orpg_windows.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import *
--- a/orpg/orpg_xml.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/orpg_xml.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,18 +21,17 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: orpg_xml.py,v 1.12 2007/07/19 20:33:10 digitalxero Exp $
+#   $Id: orpg_xml.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: xml utilies
 #
 
 from orpg import minidom
 import string
-
 from orpg.tools.orpg_log import logger, debug
 
 class xml:
-    debug('Deprecated call to orpg_xml!!')
+    debug('Developers note. Deprecated call to orpg_xml!!')
     def __init__(self):
         pass
 
--- a/orpg/player_list.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/player_list.py	Sat Apr 24 08:37:20 2010 -0500
@@ -22,12 +22,12 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: player_list.py,v 1.29 2007/03/30 19:12:06 digitalxero Exp $
+#   $Id: player_list.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $
 #
 # Description: This is the main entry point of the oprg application
 #
 
-__version__ = "$Id: player_list.py,v 1.29 2007/03/30 19:12:06 digitalxero Exp $"
+__version__ = "$Id: player_list.py,v Traipse 'Ornery-Orc' prof.ebral Exp  $"
 
 from orpg.orpg_windows import *
 from orpg.dirpath import dir_struct
--- a/orpg/templates/default_LobbyMessage.html	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_LobbyMessage.html	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
             Chris Davis, Michael Edwards, Andrew Ettinger, Dj Gilcrease, Todd Faris,
             Christopher Hickman, Paul Hosking, Scott Mackay, Brian Manning,
             Jesse McConnell, Brian Osman, Rome Reginelli, Christopher Rouse, Dave Sanders, Mark Tarrabain,
-            David Byron, and Tyler Starke.
+            David Byron, David, Vrabel, and Tyler Starke.
             </td>
               </tr>
                 <tr>
--- a/orpg/templates/default_Lobby_map.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_Lobby_map.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -1,7 +1,7 @@
 <nodehandler class="min_map" icon="compass" module="core" name="miniature Map">
 <map version='1.0' sizex='650' sizey='384' action='new'>
 <grid size='50'  mode='0' line='0' snap='1' color='#000000'/>
-<bg path='http://www.knowledgearcana.com/arcane-art/Traipse_Skeleton.png' type='2'/>
+<bg path='http://www.knowledgearcana.com/arcane-art/ornery-orc-small.png' type='2'/>
 <miniatures serial='2'/>
 </map>
 </nodehandler>
--- a/orpg/templates/default_settings.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/default_settings.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -2,9 +2,8 @@
     <tab name="General" type="tab">
         <tab name="Networking" type="grid">
             <Heartbeat options="bool" value="1" help="This sends a message to the server to keep alive your connection when idle." />
-            <MetaServerBaseURL help="This is the URL that contains the server list." options="URL" value="http://www.openrpg.com/openrpg_servers.php"/>
+            <MetaServerBaseURL help="This is the URL that contains the server list." options="URL" value="http://orpgmeta.appspot.com/"/>
             <ImageServerBaseURL help="This is the URL that contains the server list." options="URL" value="http://openrpg.digitalxero.net/imgupload/index.php"/>
-            <LocalImageBaseURL help="This is the URL that contains the server list." options="URL" value="http://127.0.0.1:6774/webfiles/"/>
             <LocalorRemote help="Decide to load files locally or remotely. CherryPy must be running for local files." options="Local | Remote" value="Local"/>
         </tab>
         <tab name="Sound" type="grid">
--- a/orpg/templates/feature.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/feature.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -1,5 +1,62 @@
-<nodehandler class="tabber_handler" icon="help" map="" module="containers" name="Traipse OpenRPG" version="1.0">
-  <nodehandler class="tabber_handler" frame="499,524,156,129" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Quick Help" version="1.0">
+<nodehandler class="tabber_handler" frame="400,400,0,48" icon="help" map="" module="containers" name="Traipse OpenRPG" version="1.0">
+  <nodehandler class="tabber_handler" frame="636,449,368,80" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
+  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
+
+This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
+
+What is OpenRPG:
+OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
+
+What is Traipse OpenRPG:
+Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
+
+Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.
+
+The User Manual:
+The user manual is divided into Chapters and Sections.  Each Chapter will go over the various features of OpenRPG and attempt to explain them in an easy to understand format.
+
+Adding to the Manual:
+Do you see something that could be explained eaiser?  Report the problem as a bug and it will be added to the manual.</text>
+</nodehandler><nodehandler class="tabber_handler" icon="player" map="Traipse OpenRPG::User Manual" module="containers" name="Chat" version="1.0"><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual::Chat" module="forms" name="Using Chat" version="1.0">
+  <text multiline="1" send_button="0">The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few.
+
+The chat includes a set of commands. You can learn about the commands by entering /help
+
+The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text.</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="ccmap" map="Traipse OpenRPG::User Manual" module="containers" name="Map" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::Map" module="forms" name="Using The Map" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
+The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
+
+When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
+
+Lurker or in the Lobby: 
+You cannot access any map tab or changes it's settings.
+
+Player: 
+You have access to the Miniatures tab and the Whiteboard tab.
+
+GM: 
+You have access to all of the tabs.
+
+The Layers:
+A small description of each of the layers.
+
+Background: 
+You can set an image as the background, an image as a tile, or you can set a color.
+
+Grid: 
+You can change the grid size, lines, turn off the grid snap, and change the grid shape.
+
+Miniatures: 
+You can add new or remove miniatures and change mini properties and labels.
+
+Whiteboard: 
+With the whiteboard you can draw lines or add text to the map.
+
+Fog: 
+The fog layer hides the entire map from the prying eyes of players.
+</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="gear" map="Traipse OpenRPG::User Manual" module="containers" name="Game Tree" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual::Game Tree" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Quick Help" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">Quick Help:
 
 The referencing system is an update to the Core of how the Game Tree works.  In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further
@@ -57,42 +114,41 @@
 In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location.
 
 This freedom will help with future design and I feel it also frees up the hands of the GM who does not need to Index, un-Index, Namespace, un-Namspace the various creatures he or she may have in a Game Tree.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Root Reference" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Root Reference" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
 Works at the tree level. Must be exact.
 
 &lt;b&gt;Root Reference 1:&lt;/b&gt; !@Reference Examples::Group::Child@!
 &lt;b&gt;Root Reference 2:&lt;/b&gt; !@Reference Examples::Grid::(2,1)@!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Grid Reference" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Grid Reference" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Grid Reference&lt;/b&gt;
 Works by looking at the (Row, Column) of a Grid.
 
 &lt;b&gt;Grid Reference 1:&lt;/b&gt; !@Reference Examples::Grid::(1,1)@!
 &lt;b&gt;Grid Reference 2:&lt;/b&gt; !!Grid::(1,1)!!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Child Reference" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Child Reference" version="1.0">
   <text hide_title="1" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Child Reference&lt;/b&gt;
 Works at the current tree location.
 
 &lt;b&gt;Child Reference 1:&lt;/b&gt; !!Group::Child!!
 &lt;b&gt;Child Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!
 </text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Parent Reference" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Parent Reference" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Parent Reference&lt;/b&gt;
-Works by indexing the map of the node with the Reference.
-Works with a Child Reference only. 
+Works by indexing the tree map of the node with the Reference. Allows you to start from a 'Parent'.
 
-&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Group_3::Child_3!!
-&lt;b&gt;Parent Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!</text>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples" module="containers" name="Group" version="1.0">
-  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
+&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Child_2!!
+&lt;b&gt;Parent Reference 2:&lt;/b&gt; !#Bonus Nodes::Deck::Draw#!</text>
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="containers" name="Group" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
   <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
   <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
-</nodehandler></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="forms" name="Child" version="1.0">
+</nodehandler></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group" module="forms" name="Child" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
-</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell size="147">0</cell>
@@ -106,50 +162,7 @@
   <macros>
     <macro name="" />
   </macros>
-</nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
-  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
-
-This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
-
-What is OpenRPG:
-OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
-
-What is Traipse OpenRPG:
-Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
-
-Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using Chat" version="1.0">
-  <text multiline="1" send_button="0">The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few.
-
-The chat includes a set of commands. You can learn about the commands by entering /help
-
-The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text.</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using The Map" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
-The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
-
-When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
-
-Lurker or in the Lobby: You cannot access any map tab or changes it's settings.
-
-Player: You have access to the Miniatures tab and the Whiteboard tab.
-
-GM: You have access to all of the tabs.
-
-The Layers:
-A small description of each of the layers.
-
-Background: You can set an image as the background, an image as a tile, or you can set a color.
-
-Grid: You can change the grid size, lines, turn off the grid snap, and change the grid shape.
-
-Miniatures: You can add new or remove miniatures and change mini properties and labels.
-
-Whiteboard: With the whiteboard you can draw lines or add text to the map.
-
-Fog: The fog layer hides the entire map from the prying eyes of players.
-</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
+</nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual::Game Tree" module="forms" name="Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
 
 Grid Nodes:
   Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@!
@@ -180,7 +193,7 @@
 
   Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
 
-Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
+Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
 
 (Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map)
 
@@ -232,7 +245,7 @@
 
 Examples: 
 !@Kammen-Pai::Cast::Ray of Frost@!
-!@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Setting up a Server" version="1.0">
+!@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler></nodehandler><nodehandler class="tabber_handler" icon="labtop" map="Traipse OpenRPG::User Manual" module="containers" name="The Server" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::The Server" module="forms" name="Setting up a Server" version="1.0">
   <text multiline="1" send_button="0">In Traipse starting a server has never been easier.  The setup is as easy as 1., 2., 3
 
 1. You will need to first start the Server GUI or the basic text based Server at least once so your software creates the server_ini.xml files in your myfiles directory. You can start it once and quit.
@@ -244,15 +257,13 @@
 3. This is the hardest step. You need to make sure your selected port is forwarded by your router and open to your firewall.
 
 That's it! You can now start the server and register it to the meta for all users to enjoy!</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Adding to the Manual" version="1.0">
-  <text multiline="1" send_button="0">Do you see something that could be explained eaiser?  Report the problem as a bug and it will be added to the manual.</text>
-</nodehandler><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Release Notes" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,0,48" icon="browser" map="Traipse OpenRPG::User Manual" module="containers" name="Links" version="1.0"><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Release Notes" version="1.0">
     <link href="http://www.assembla.com/wiki/show/traipse" />
   </nodehandler>
-  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual" module="forms" name="Traipse User Guide" version="1.0">
+  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Traipse User Guide" version="1.0">
     <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
   </nodehandler>
-  </nodehandler><nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
+  </nodehandler></nodehandler><nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
   <nodehandler class="form_handler" frame="514,464,307,57" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
   <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
   <list hide_title="0" raw_mode="1" send_button="1" type="1">
@@ -322,10 +333,12 @@
   <text multiline="1" send_button="1">Kobolds a plenty.</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 1" version="1.0">
   <text multiline="1" send_button="1">A Wandering Minotaur</text>
-</nodehandler></nodehandler></nodehandler></nodehandler><nodehandler class="file_loader" icon="help" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
+</nodehandler></nodehandler></nodehandler></nodehandler><nodehandler class="file_loader" icon="book" map="Traipse OpenRPG" module="core" name="Load User Manual" version="1.0">
+  <file name="Traipse_User_Guide.xml" />
+</nodehandler><nodehandler class="file_loader" icon="d10" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
     <file name="die_roller_notes.xml" />
   </nodehandler>
-  <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" icon="grid" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
     <nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Templates" module="containers" name="PC Sheets" version="1.0">
   <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create 4e PC Sheet" version="1.0">
         <file name="4e_char_sheet.xml" />
@@ -372,16 +385,16 @@
         <file name="form.xml" />
       </nodehandler>
     </nodehandler>
-    <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Die Macro" version="1.0">
-        <file name="die_macro.xml" />
-      </nodehandler><nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
+    <nodehandler border="1" class="group_handler" cols="1" icon="grenade" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
+      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create File Loader" version="1.0">
+    <file name="file_loader.xml" />
+  </nodehandler><nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
         <file name="macro.xml" />
       </nodehandler>
       <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Miniature Library Tool" version="1.0">
         <file name="minlib.xml" />
       </nodehandler>
-      <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create remote node loader" version="1.0">
+      <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>
--- a/orpg/templates/metaservers.cache	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/metaservers.cache	Sat Apr 24 08:37:20 2010 -0500
@@ -1,1 +1,1 @@
-http://www.openrpg.com/openrpg_servers.php 1 2
+http://orpgmeta.appspot.com 1 2
--- a/orpg/templates/nodes/4e_char_sheet.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/4e_char_sheet.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -1,4 +1,4 @@
-<nodehandler class="tabber_handler" frame="808,494,162,44" icon="tabber" map="" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="tabber_handler" frame="400,400,399,89" icon="tabber" map="4e PC Sheet" module="containers" name="Using the 4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This node is designed to be as generic as possible. It should contain the core basics for users to fill out with game information that is specific to their character.
+<nodehandler class="tabber_handler" frame="808,494,166,146" icon="tabber" map="" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="tabber_handler" frame="400,400,399,89" icon="tabber" map="4e PC Sheet-WIP" module="containers" name="Using the 4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This node is designed to be as generic as possible. It should contain the core basics for users to fill out with game information that is specific to their character.
 
 The node is also designed to be organized with speed of use in mind. Since the majority of nodes are inside Tabbers you can easily use the top node and find all of your data inside. In fact, that is how I am writing this.
 
@@ -13,7 +13,7 @@
 
 Combat: This contains grids so you can reference your weapon dice, armor bonuses, feat bonuses .. and they too can use references so if you change a number the software does the math.
 
-Inventory: You guess it.  It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Rollers" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">Inside the Rollers tab you will find 5 lists. You can use these lists to add new references to nodes.  The Rollers tab is also a Tabber node itself, so you can just double click the Rollers node to get all of your rollers in one window.  You can also edit all of your rollers in one window when you enter into the Design mode of the Rollers tabber.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="General" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This form contains a some text nodes that hold basic information about your character. In some Powers the Level and Tier are used to calculate bonuses. You can reference those nodes to make the math easier</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Abilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Abilities Grid contains the 6 abilities all set at values of 8. The third column is the math calculation for the modifier. You can reference that grid column to assist in your math calculations.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Combat" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Combat Tabber contains a number of Grid nodes to assist in your combat calculations. Some grids contain a grid cell called Total.
+Inventory: You guess it.  It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Rollers" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">Inside the Rollers tab you will find 5 lists. You can use these lists to add new references to nodes.  The Rollers tab is also a Tabber node itself, so you can just double click the Rollers node to get all of your rollers in one window.  You can also edit all of your rollers in one window when you enter into the Design mode of the Rollers tabber.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="General" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This form contains a some text nodes that hold basic information about your character. In some Powers the Level and Tier are used to calculate bonuses. You can reference those nodes to make the math easier</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Abilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Abilities Grid contains the 6 abilities all set at values of 8. The third column is the math calculation for the modifier. You can reference that grid column to assist in your math calculations.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Combat" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Combat Tabber contains a number of Grid nodes to assist in your combat calculations. Some grids contain a grid cell called Total.
 
 To Hit: The To Hit Bonus. This Grid contains a cell called Total. You can add new rows to the grid when you are granted bonuses and then add those references to the total. 
 
@@ -23,54 +23,124 @@
 
 AC Bonus: This Grid contains a cell called Total. You can add new rows to the grid when you are granted bonuses and then add those references to the total. 
 
-Feats: Some feats add bonusus to hit or damage.  When these bonuses are calculated you can add them here and the math easier for you.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Utilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This Tabber contains a Tabber for At Will, Encounter and Daily.  Each tabber contains a node for levels 0 and 1.  You can add new tabbers when you reach higher levels.
+Feats: Some feats add bonusus to hit or damage.  When these bonuses are calculated you can add them here and the math easier for you.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Utilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This Tabber contains a Tabber for At Will, Encounter and Daily.  Each tabber contains a node for levels 0 and 1.  You can add new tabbers when you reach higher levels.
 
 Inside the 0 Level tabber for each Utility there is a text node that contains a an attack roll and a damage roll. 
 
-** I went with this format so users could create their Utility nodes and share with others. The nodes can contain Role Play information as well as attack and damage rolls. Also, the nodes can be completely genric, referencing the Name Text node and still look specific **</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Inventory" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">It's just a node to hold your Inventory
+** I went with this format so users could create their Utility nodes and share with others. The nodes can contain Role Play information as well as attack and damage rolls. Also, the nodes can be completely genric, referencing the Name Text node and still look specific **</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet-WIP::Using the 4e PC Sheet" module="forms" name="Inventory" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">It's just a node to hold your Inventory
 
 This bears repeating:
-It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="437,400,373,67" icon="tabber" map="4e PC Sheet" module="containers" name="Rollers" version="1.0"><nodehandler class="listbox_handler" frame="400,400,430,57" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Skills" version="1.0">
-        <list raw_mode="1" send_button="1" type="1">
-          <option caption="" selected="1" value="0">Climb [1d20+5+!#Abilities::(1,3)#!+(!#General::Level#!/2)</option>
-          <option caption="" selected="0" value="0">Hide [1d20+5+!#Abilities::(2,3)#!+(!#General::Level#!/2)]</option>
-          <option caption="" selected="0" value="0">Spot [1d20+5+!#Abilities::(4,3)#!+(!#General::Level#!/2)]</option>
+It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="568,400,446,121" icon="tabber" map="4e PC Sheet-WIP" module="containers" name="Rollers" version="1.0"><nodehandler class="listbox_handler" frame="400,400,541,107" icon="gear" map="4e PC Sheet-WIP::Rollers" module="forms" name="Skills" version="1.0">
+        <list raw_mode="1" send_button="1" type="2">
+          <option caption="Climb" selected="0" value="0">Climb [1d20+5+!#Abilities::(1,3)#!+(!#General::Level#!/2)]</option>
+          <option caption="Hide" selected="0" value="0">Hide [1d20+5+!#Abilities::(2,3)#!+(!#General::Level#!/2)]</option>
+          <option caption="Spot" selected="1" value="0">Spot [1d20+5+!#Abilities::(4,3)#!+(!#General::Level#!/2)]</option>
         </list>
       </nodehandler>
-      <nodehandler class="listbox_handler" frame="400,400,477,43" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Attacks" version="1.0">
+      <nodehandler class="listbox_handler" frame="400,400,466,138" icon="gear" map="4e PC Sheet-WIP::Rollers" module="forms" name="Attacks" version="1.0">
   <list raw_mode="1" send_button="1" type="1">
-    <option caption="Sword Attack" selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(2,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(2,2)#!]</option>
-    <option caption="Mace Attack" selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(3,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(3,2)#!]</option>
+    <option caption="Sword Attack" selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(2,1)#! [1d20+!#Combat::To Hit::(2,2)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(2,2)#!+!#Abilities::(1,3)#!]</option>
+    <option caption="Mace Attack" selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(3,1)#! [1d20+!#Combat::To Hit::(2,2)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(3,2)#!+!#Abilities::(1,3)#!]</option>
     <option caption="Uncreated" selected="0" value="">Option Text III</option>
   </list>
-</nodehandler><nodehandler class="splitter_handler" frame="764,400,9,91" horizontal="0" icon="divider" map="4e PC Sheet::Rollers" module="containers" name="Powers" version="1.0">
-    <nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="At Wills" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
+</nodehandler><nodehandler class="splitter_handler" frame="764,400,9,91" horizontal="0" icon="divider" map="4e PC Sheet-WIP::Rollers" module="containers" name="Powers" version="1.0">
+    <nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet-WIP::Rollers::Powers" module="forms" name="At Wills" version="1.0">
+  <list raw_mode="1" send_button="1" type="3">
     <option caption="At Will Power" selected="1" value="0">!#Utilities::At Will::0::At Will#!</option></list>
-</nodehandler><nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Encounters" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet-WIP::Rollers::Powers" module="forms" name="Encounters" version="1.0">
+  <list raw_mode="1" send_button="1" type="3">
     <option caption="Encounter" selected="1" value="0">!#Utilities::Encounter::0::Encounter#!</option></list>
-</nodehandler><nodehandler class="listbox_handler" frame="400,400,470,62" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Dailys" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,470,62" icon="gear" map="4e PC Sheet-WIP::Rollers::Powers" module="forms" name="Dailys" version="1.0">
+  <list raw_mode="1" send_button="1" type="3">
     <option caption="Daily" selected="1" value="0">!#Utilities::Daily::0::Daily#!</option></list>
-</nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet" module="forms" name="General" version="1.0" width="400">
-  <nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Name" version="1.0">
+</nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet-WIP" module="forms" name="General" version="1.0" width="400">
+  <nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Name" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">text</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Player" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Player" version="1.0">
   <text multiline="0" send_button="0">text</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Race" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Race" version="1.0">
+  <text multiline="0" send_button="0">text</text>
+</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Class" version="1.0">
   <text multiline="0" send_button="0">text</text>
-</nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Class" version="1.0">
-  <text multiline="0" send_button="0">text</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Level" version="1.0">
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Level" version="1.0">
+  <text multiline="0" raw_mode="1" send_button="0">1</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet-WIP::General" module="forms" name="Tier" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">1</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Tier" version="1.0">
-  <text multiline="0" raw_mode="1" send_button="0">1</text>
-</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet" module="rpg_grid" name="Abilities" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet-WIP" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="400,400,269,110" icon="grid" map="4e PC Sheet-WIP::Combat" module="rpg_grid" name="Weapons" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Weapon</cell>
+      <cell>Damage</cell>
+    </row>
+    <row version="1.0">
+      <cell>Sword</cell>
+      <cell>d6</cell>
+    </row>
+  <row version="1.0"><cell>Mace</cell><cell>d8</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet-WIP::Combat" module="rpg_grid" name="To Hit" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell size="360">Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!To Hit::(3,2)!! + !!To Hit::(4,2)!!</cell>
+    </row>
+  <row version="1.0"><cell>BAB</cell><cell>15</cell></row><row version="1.0"><cell>Str Mod</cell><cell>!#Abilities::(1,3)#!</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet-WIP::Combat" module="rpg_grid" name="AC Bonus" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell size="225">Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!AC Bonus::(3,2)!!+!!AC Bonus::(4,2)!!</cell>
+    </row>
+  <row version="1.0"><cell>Armor</cell><cell>!!Armor::(2,2)!!</cell></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet-WIP::Combat" module="rpg_grid" name="Armor" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell size="183">Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!Armor::(3,2)!!</cell>
+    </row>
+  <row version="1.0"><cell>Base</cell><cell>10</cell></row><row version="1.0"><cell>Armor</cell><cell /></row><row version="1.0"><cell>Shield</cell><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row><row version="1.0"><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet-WIP::Combat" module="rpg_grid" name="Feats" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell>Bonus</cell>
+    <cell>Descripton</cell></row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!Feats::(3,2)!!</cell>
+    <cell /></row>
+  <row version="1.0"><cell>Feat</cell><cell>0</cell><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row><row version="1.0"><cell /><cell /><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet-WIP" module="rpg_grid" name="Abilities" version="1.0">
         <grid autosize="1" border="1">
           <row version="1.0">
             <cell>Str</cell>
-            <cell>8</cell>
+            <cell>12</cell>
           <cell size="197">(!!Abilities::(1,2)!!-10)/2</cell></row>
           <row version="1.0">
             <cell>Dex</cell>
@@ -78,11 +148,11 @@
           <cell>(!!Abilities::(2,2)!!-10)/2</cell></row>
           <row version="1.0">
             <cell>Con</cell>
-            <cell>8</cell>
+            <cell>14</cell>
           <cell>(!!Abilities::(3,2)!!-10)/2</cell></row>
           <row version="1.0">
             <cell>Int</cell>
-            <cell>8</cell>
+            <cell>18</cell>
           <cell>(!!Abilities::(4,2)!!-10)/2</cell></row>
           <row version="1.0">
             <cell>Wis</cell>
@@ -96,88 +166,24 @@
         <macros>
           <macro name="" />
         </macros>
-      </nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="To Hit" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Armor</cell>
-      <cell>Bonus</cell>
-    </row>
-    <row version="1.0">
-      <cell>Total</cell>
-      <cell>!!To Hit::(2,3)!! + !!To Hit::(2,4)!!</cell>
-    </row>
-  <row version="1.0"><cell>BAB</cell><cell>0</cell></row><row version="1.0"><cell>Str Mod</cell><cell>!#Abilities::(1,3)#!</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,269,110" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Weapon</cell>
-      <cell>Damage</cell>
-    </row>
-    <row version="1.0">
-      <cell>Sword</cell>
-      <cell>d6</cell>
-    </row>
-  <row version="1.0"><cell>Mace</cell><cell>d8</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="AC Bonus" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Armor</cell>
-      <cell>Bonus</cell>
-    </row>
-    <row version="1.0">
-      <cell>Total</cell>
-      <cell>!!AC Bonus::(2,3)!!</cell>
-    </row>
-  <row version="1.0"><cell>Misc</cell><cell>0</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Armor" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Armor</cell>
-      <cell>Bonus</cell>
-    </row>
-    <row version="1.0">
-      <cell>Total</cell>
-      <cell>!!Armor::(2,3)!!</cell>
-    </row>
-  <row version="1.0"><cell>Base</cell><cell>10</cell></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Feats" version="1.0">
-  <grid autosize="1" border="1">
-    <row version="1.0">
-      <cell>Armor</cell>
-      <cell>Bonus</cell>
-    <cell>Descripton</cell></row>
-    <row version="1.0">
-      <cell>Total</cell>
-      <cell>!!Feats(2,3)!!</cell>
-    <cell /></row>
-  <row version="1.0"><cell>Feat</cell><cell>0</cell><cell /></row></grid>
-  <macros>
-    <macro name="" />
-  </macros>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,407,67" icon="tabber" map="4e PC Sheet" module="containers" name="Utilities" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="At Will" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::At Will::0" module="forms" name="At Will" version="1.0">
+      </nodehandler><nodehandler class="tabber_handler" frame="400,400,407,67" icon="tabber" map="4e PC Sheet-WIP" module="containers" name="Utilities" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities" module="containers" name="At Will" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::At Will" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet-WIP::Utilities::At Will::0" module="forms" name="At Will" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an At Will
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Encounter" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Encounter::0" module="forms" name="Encounter" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::At Will" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities" module="containers" name="Encounter" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::Encounter" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet-WIP::Utilities::Encounter::0" module="forms" name="Encounter" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an Encounter
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Daily" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Daily::0" module="forms" name="Daily" version="1.0">
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::Encounter" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet-WIP::Utilities" module="containers" name="Daily" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::Daily" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet-WIP::Utilities::Daily::0" module="forms" name="Daily" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">/me uses an Daily
 &lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
 &lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="1" version="1.0" /></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Inventory" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory" module="forms" name="Back Pack" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">Empty.</text>
-</nodehandler></nodehandler></nodehandler>
\ No newline at end of file
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet-WIP::Utilities::Daily" module="containers" name="1" version="1.0" /></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet-WIP" module="containers" name="Inventory" version="1.0"><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet-WIP::Inventory" module="containers" name="Back pack" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet-WIP::Inventory::Back pack" module="forms" name="Slot 1" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet-WIP::Inventory::Back pack" module="forms" name="Slot 2" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet-WIP::Inventory" module="containers" name="Belt" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet-WIP::Inventory::Belt" module="forms" name="Slot 1" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet-WIP::Inventory::Belt" module="forms" name="Slot 2" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Nothing</text>
+</nodehandler></nodehandler></nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/templates/nodes/Idiots_guide_to_openrpg.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,267 +0,0 @@
-
-<nodehandler class="static_handler" module="core" name="Idiot's Guide, 0.9.4" status="useful">
-  <group_atts border="1" cols="1"/>
-  <nodehandler class="text_handler" icon="note" module="core" name="Table of contents:">&lt;a href=&quot;#c1&quot;&gt;Chapter 1:&lt;/a&gt; Chatting up them OpenRPGers
-&lt;a href=&quot;#c2&quot;&gt;Chapter 2:&lt;/a&gt; Rolling those dice and whispering those sweet nothings
-&lt;a href=&quot;#c3&quot;&gt;Chapter 3:&lt;/a&gt; Creating your own Character sheet
-&lt;a href=&quot;#c4&quot;&gt;Chapter 4:&lt;/a&gt; Opening your own room and sharing your character with all
-&lt;a href=&quot;#c5&quot;&gt;Chapter 5:&lt;/a&gt; Advanced stuffs (like pictures)
-&lt;a href=&quot;#c6&quot;&gt;Chapter 6:&lt;/a&gt; Setting up your own server</nodehandler>
-  <nodehandler class="text_handler" icon="note" module="core" name="Introduction">Welcome, Mateys, to the online gaming universe of the OpenRPG!  By now you have successfully downloaded and installed the program or you would not be able to read this document.  But we are not here to discuss what you already know, we are here to get around to telling you how to do those things you don't know.
-
-&lt;b&gt;What we'll cover in this guide:&lt;/b&gt;
-1)How to use the basic OpenRPG
-2)How to do those really nifty advanced things in OpenRPG
-3)How to get your brother to do those nifty things in OpenRPG while you beat him with a whip
-4)Getting along with those others on the OpenRPG program
-
-And, before long, before you know it, and before that chicken in the microwave is done, you will know and have mastered the art of using OpenRPG.</nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 1:OpenRPG Basics">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="Chapter 1:  OpenRPG and you">&lt;a name=&quot;c1&quot;&gt;&lt;/a&gt;
-Alright.  Let us start at the beginning.  Many many years ago the dinosaurs roamed the planet.  But then an asteroid, now most commonly known as &quot;Bill Gates 1,&quot; crashed into the earth and wiped them all out, turning them into oil.  The basic upshot of all that is with this oil we have created electricity which is now running the program.
-
-Before we start it is nessessary to make a name for yourself.  Why?  Well, you wouldn't like to be going around with everybody knowing only as 'blankman' would you?  To type in your name, go up to the top left window, and dragging donw the &quot;OpenRPG&quot; menu bar press &quot;settings&quot;.  in there you can alter your name and colours.  Whenever you wish to change your name, you must first disconnect from any server (We'll get to servers and conenction next paragraph)) then reconnect before the change occurs.
-
-You can also rename yourself in a much more simple way by typing in the command &quot;/name &quot; and your name behind it in the chat window.  I just made you go into the settings so that you know where they are later.
-
-Now that you have yourself labled, you are probably wondering &quot;where's all the chat?&quot;  Well, my friend, we are here to answer that.  As your program booted up, it should have brought up a window marked &quot;OpenRPG&quot; in the top left, a &quot;Player list&quot; in the bottom left, a map on the top right, and a chat screen on the lower right.  We will first concern outselves with getting that lower right window to do the work and play with the others later.
-
-To get the chat window to work, first we actually need a place to chat.  To do this, we need to browse the list of rooms on what is known as the &lt;i&gt;Tracker&lt;/i&gt;.  To open the tracker window go to the &quot;OpenRPG&quot; window and under the menu &quot;Game Server&quot; click on &quot;Browse Tracker&quot;
-
-As you can see, a new window popped up.   This is the &lt;i&gt;Tracker Window&lt;/i&gt;.  On the left you will see a list of various servers running OpenRPG online.  Click on the one at the top of the list and press &quot;Connect&quot;.
-
-After pressing the &quot;Connect&quot; button you will join that server and be instantly dropped into it's lobby.  Welcome to your first chatroom.  Feel free to stay in this room as long as you like or move off to another room listed on the Tracker.  When you first turned on OpenRPG the chat window filled up with all the different chat commands available.  If you are like me and have forgotten them by now you can either click on the little text entry box and press &lt;i&gt;Page Up&lt;/i&gt;   or type in &lt;i&gt;/help&lt;/i&gt;.  Should you wish a way to scroll up instead of 'page up'ing you can increase the amount of lines the Chat Window stores by making the &lt;i&gt;Buffer Size&lt;/i&gt; larger.  Either do this in the settings window or in the chatwindow itself and it will be saved for the next time you use OpenRPG.
-
-By now I'm sure you are also wondering what that &lt;i&gt;status&lt;/i&gt; thingy in the bottom left window is.  If you notice, every time you type a message in the chat window your status changes.  And when you finish your msg (or sit for 5 seconds waiting) it changes back to Idle.  What a clever invention.  Of course, if you wish to set your own status to override &quot;Idle&quot; temporarily, just type in the chat window &quot;/status My_Status&quot;; replacing &quot;My_Status&quot; for whatever msg you wish (no more than 13 letters can be seen though).
-
-As for now, spend some time and enjoy yourself in the lobby... we can come back to the tutorial when you are ready to learn about Rolling dice, whispering, and creating and using character sheets.</nodehandler>
-  </nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 2: Dice Rolling and Whispering">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="Ah, you're back!">&lt;/a name=&quot;c2&quot;&gt;&lt;/a&gt;
-I'm astonished.  82% of all people who use this program never bother to read the tutorial, let alone come back to it.  Then again 67% of all statistics are made up on the spot so we'll leave that for now and get on with what we are doing
-
-Now, to get back to business.  By now you've hopefully held a conversation with someone (or at least yourself) in our chatroom and now I'm sure you're wondering &quot;How can I roll some dice so I can smite those foolish mortals.&quot;  Well, don't be discouraged, because that is what I'm here for.
-
-To roll dice you have two options.  you can simply press the button on the dice toolbar  or you can type in how many times you wish to roll.  As pressing buttons is mostly self explanitory, this part will only cover typing in dicerolls.
-
-First we will choose how many dice we wish to roll at once.  To say how many dice you wish to roll, just type in the number ((say.. 1))... so it would look like this:
-
-1
-
-now tell the type of dice you wish to roll.  to do this you write a 'd' ((d for dice)) and the number of sides that dice has.  Say I want to roll a 20 sided dice that one time it would look like this:
-
-1d20
-
-Now put those square brackets around it.  They are the ones directly to the right of the &quot;P&quot; key.  ((for quick reference on what I mean, find chapter two in this guide, right click-edit it, and look at how I have the dice written in the text blocks))
-
-[1d20]
-
-hope I rolled well.  I know it looks like those round brackets above the '9' and '0' keys but to type it in you need to use square brackets between the &quot;P&quot; and &quot;\&quot; keys.  All you do is type that in the into the chat text box and it will automatically roll it for you.  You could even do combinations of dice or simple mathmatics inside the dice macro as well...
-
-[4d20+1d10]
-
-[1d8-4]
-
-[6d4+3]
-
-[1d10*10]
-
-[(1d10+5)+(6d4-3)-12]
-
-Now that you have gotten the basics of the dice roll down, let us move on to some more advanced stuff.  What I'm talking about is mainly for Whitewolf players, but good to know anyway.
-
-let's take a dice roll, shall we.  Let's roll 5d10:
-
-[5d10]
-
-as you can see, I used a lowercase &quot;d&quot; and it came up with each dice roll and the sum of all of them.  Let's change that by capitalising the &quot;D&quot; shall we:
-
-[5D10]
-
-As you can see, instead of giving us a sum of all the dice, it instead told us what each dice had rolled.  This is useful if you want individual dice rolls shown rather than a final result.
-
-Now that we have that basis down, we are going to set up the dice macro so that it compares how many dice have gotten over a number you tell it.  you'll see what I mean in this demonstration:
-
-[5D10 vs 7]
-
-All that was added was the capital &quot;D&quot; and add the words &quot;vs 7&quot;.  Of course, you can change the number to whatever you wish.  You will also notice, when you use it, that it will automatically detract the result for every '1' you roll on the dice.  So if you rolled 5D10 and got a 7, an 8, a 9, and two '1's with a &quot;vs 7&quot; you would only have one success.
-
-Now for those of you who play AEG's Legend of the 5 Rings RPG (and possibly their other games), your probably wondering how do I handle rolling for L5R. No worries there, we've got you covered. The syntax is the same as in the rule book. Say we want to roll 5 dice and keep only 2, we type that in as:
-
-[5k2]
-
-This will roll 5d10 and keep the highest 2 dice, and will handle the re-rolling of any 10's. But what about all those unskilled and similar skill rolls you need to make, where you can't re-roll the 10's. It only takes a small change to the previous roll. We just tack on a 'u' to the end, like so:
-
-[5k2u]
-
-
-</nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;Need to tell that special someone that you like them but don't want the room to hear?&lt;/u&gt;&lt;/b&gt;">Well, the designer of OpenRPG thought of such eventualities, and has provided us with the ability to whisper at will to whoever is in the room.  Doing so is quite easy in it's own way, and we'll show you here.
-
-All that is required is for you to type in a &lt;i&gt;/w&lt;/i&gt; then the person's name ((Caps are important!!!)), an equals sign (( = )) and then your message... so it would probably look something like this:
-
-&lt;i&gt;/w Monkeyman=&lt;/i&gt;I think that Woody person that is usually in the Lobby is soo cute
-
-&lt;i&gt;/w Susan=&lt;/i&gt;yeah, but I hear he likes bananas so I won't go near him
-
-And there we go.  But I can hear your cries &quot;What about those people that have extrodinarily annoying names?&quot;  Well, do not fret... just go over to your player list in the lower lefthand corner and right click on the little heads next to their name.  Magically, one of those menu bars will appear and give you the option to whisper to them.  Press it and watch as the '/w' command comes up in the chat text box.  How nice!
-
-And should you wish to whisper to more than one person, just add each name after the initial '/w' and put commas between them, like so:
-
-&lt;i&gt;/w Susan, Monkeyman, Thatotherguy=&lt;/i&gt;Vote Woody for Overlord 2001!!!
-
-simple as that. You could even whisper dice the exact same way.
-
-Stay tuned for the next chapter where we get into how to create, use, and abuse your own character sheets.</nodehandler>
-  </nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 3: Nodes and Character Sheets">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;The Basics&lt;/b&gt;">&lt;a name=&quot;c3&quot;&gt;&lt;/a&gt;
-alright.. by now you have grasped the basics on how to chat, so we will move on to the next phase: character sheets.  This part of the tutorial will cover how to make a full usable document from the nodes.
-
-Let us first start by describing what the different nodes are and where we can find them:</nodehandler>
-    <nodehandler class="static_handler" module="core" name="The Nodes">
-      <group_atts border="1" cols="4"/>
-      <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;the Group Node&lt;/u&gt;&lt;/b&gt;">as we look at the various nodes they all appear to be stored in a blue bottled icon called &quot;Wizards&quot;.  Wizards itself is a group node and it shows the function of the 'group': to store and combine all the nodes which would otherwise just float randomly on the Gametree.
-
-When we make a group, we do so so that we can store our information into one well organized array rather than a collection of scattered files.</nodehandler>
-      <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;Text Block&lt;/u&gt;&lt;/b&gt;">The text block is where we will be storing most of our text information.  It allows you to type in words, paragraphs, or entire pages of information you want to keep on your character sheet without the needless bother of grids.  If you look carefully you will notice that the Dice Macro box is also just another Text Box but with some dice in it.  You are fully able to put any dice on here in any place in the Text Body and when the character sheet is opened you will see that the dice has been rolled.</nodehandler>
-      <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;The Grid&lt;/u&gt;&lt;/b&gt;">Now, text boxes are all well and good for storing words and paragraphs, but for easy storage of numbers that we use for reference there is nothing better than a Grid.  The grid allows us to set up any manner of chart or graph to for quick reference and study.</nodehandler>
-      <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;The Macro Node&lt;/u&gt;&lt;/b&gt;">The Macro Node works just like a normal text box node, but instead of seeing it in it's own window, everything that is typed into it is broadcast directly into the chat window as if you were saying it.  This includes actions, whispers, status changes, etc.  Good if you want to change names or perform series of speeches and actions in order just by doubleclicking on a node.  We won't be getting to know them in this, but they are pretty self explanitory.  Just doubleclick to use them and right click to edit.</nodehandler>
-    </nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;Pick your Nodes and Eat It Too&lt;/u&gt;&lt;/b&gt;">Now that you know what the various nodes are, I'm sure you're asking &quot;how do I use then then?&quot;  Well, let us start with the main node, the Group.
-
-To create a group doubleclick on the &quot;New Group&quot; Node in the Wizards tree.  you will see that a new &quot;Group&quot; has appeared at the top in the main Gametree.  Open the new group by doubleclicking on it.
-
-.........
-
-Oh my... all rather empty, isn't it?  maybe we should fill it up with something.  Let's make a text box to put in that void, shall we?  Alright.   Go into the Wizards directory again and doubleclick on the &quot;New Text Block&quot;.  Again you will see a Text Block has appeared at the top in the gametree.  Doubleclick on it to see what's inside.
-
-.........
-
-again it all seems very flat.  I don't like that text in there so let's change it.  this time rightclick on the Text Block and press &quot;Edit&quot;.  Voila!!  You will see an 'edit' box where you can change the title and the text body, with lots of little extras down below.  Go ahead and type in a new title and message for yourself.
-
-Now that you have added your personal message to the world it is time to add it to your group.  Close down the Text Box Editor (it automatically saves, so just hit the 'x' button) and look up to your gametree again.  Once you see it, grab your new edited Text Box and drag it into the group that you created earlier.  Now doubleclick on the group and marvel at your creation.  Congratulations on making your first character sheet.
-
-**Note.  To edit everything in a group at once just right click on the group and press Edit.**</nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;That's It?!?&lt;/u&gt;&lt;/b&gt;">&quot;That's it?!  I want my money back!  In fact, since it was free, I want you to give me money to compensate for having to read this long tutorial just for that!!!&quot;  Is what I'm sure you're thinking right now.  But don't worry, our character sheets will be getting much more complex and much better looking from this point out.
-
-Turning back to our creation, we have a Group with a single Text box inside it.  Now, I like that message you have typed in there, so let's double it's voice across the program.  Right click on the text box inside the group you created, and press &quot;clone&quot;.  Voila again!!!  You'll see an exact copy of your message has appeared at the top of the Gametree.  Grab that Text box and Drag it onto the Group as well.  Now open up your group by doubleclicking on it and take a look again at what you have created.
-
-.....
-
-Hhhmmm.... It's all very well and dandy, but it's going to get a little long, isn't it.  If each item we put in there is going to be lined up straight down this thing is going to be pages in length.  Well, luckily for you, we have a way around that.  closing down your group window let us look up to the Gametree again.  This time, instead of doubleclicking on the Group, right click on it.  You'll see it brings up the same menubar as what the textbox had.  Don't worry, we'll get to play with all the nifty features later.  Go down and press edit.
-
-A little edit box should have popped up with Three Options.  The first is to rename the Group, the second dictates how many columns we can have (1-4), and the third just asks if we want borders.  Lets first change the name of our group to &quot;Lagmonkey's Group&quot;.  Then, lets change the 'Columns&quot; from one to two then close down the edit box.  Open up the Group again and look now as it appears the two text messages are side by side.  How convenient!  In fact, as you saw you can have up to four things side by side at the same time.  Any further Nodes inside the group ((the 5th one and beyond)) will just get put in one of the columns under the first four, in order.</nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;Ah, but will she swallow it, Stevie Wonder?&lt;/u&gt;&lt;/b&gt;">Now that we have our simple group with it's two columns and it's text boxes, it's time to add a Grid, I think.  create a grid the same way as we did the Text Box and the group, then go in and edit it.  What we want is a Grid that looks exactly like this:</nodehandler>
-    <nodehandler class="rpg_grid_handler" icon="grid" module="rpg_grid" name="Grid">
-      <grid border="1">
-        <row>
-          <cell>I</cell>
-          <cell>Really</cell>
-          <cell>Love</cell>
-          <cell>Bananas</cell>
-          <cell>Matey!</cell>
-        </row>
-      </grid>
-      <macros>
-        <macro name=""/>
-      </macros>
-    </nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name=" ">Be sure to add three extra columns for the words by pressing the &quot;Add Columns&quot; button.  Oh, and get rid of that bottom row, we don't need it right now (though, if you wish, you are welcome to put numbers in the bottom row instead of removing it for practice if you like.)
-
-Now that we have our grid, let's drag it onto our group and open up our group, shall we?  Oh my.. the Bananas are overlapping, aren't they?  It appears the column isn't wide enough to support a grid so wide.  But I like bananas, so we are going to have to keep the grid.  What we need would be a nice large column to hold it though, so let's make one.
-
-Go into the Wizards again and create another new group.  Now drag the Grid over onto the new group, then picku p and drag &quot;Lagmonkey's Group' onto the new group.  yes, matey, a group within a group.  Open it up and see what the result is.  Interesting.  It appears that the grid and the two columns are all inside the new group's main column.  We could continue to stack columns into each other into infinity, though it would get increasingly hard to read.
-
-Getting back, you can now see the grid is on top and Lagmonkey's group is on the bottom.  I don't like that arrangement so let's change it.  Close down the New Group box then on the gametree grab the grid and drag it onto the new group's icon once again.  You'll see that that had the effect of re-adding the grid to the new group, this time placing it at the bottom.  Whenever you add something to a group, it always appears at the bottom.</nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;&lt;u&gt;That's it!&lt;/u&gt;&lt;/b&gt;">That's basically it for making character sheets.  Feel free to experiment with various combinations of items and settings.. add and remove borders to see what you like.. create grids of varous sizes and shapes and stick them into your columns...perhaps put some dice in those text boxes of yours ((with the appropriate &quot;[3d6]&quot;  around them))... but most of all: Have fun!
-
-**Note: Be sure to save your character sheet if you want to.  To do so, right click on it and press &quot;Save Node&quot;**</nodehandler>
-    <nodehandler class="text_handler" icon="note" module="core" name="Moving Characters from almost ANY Character Generator to here.">The following are stpes on how to move your character sheets from your favorite Character Generation program into OpenRPG.  It's very quick and clean cut.
-
-1) first, using your character generator, you convert your character to either txt format, or, preferably (if you have the ability) HTML format.
-
-2) Then, you go to wizards.put a text block into the gametree
-
-3) if you are using txt, select all, and copy.  if you are using HTML format, edit it using notepad, but don't change any of the HTML Program. then select all and copy
-
-4) now, going back into OpenRPG, right click on the text block you created and push 'edit'
-
-5) clear the text block of the few words of text that appear there then paste the copied info into by either rightclicking-paste or pressing 'ctrl v'
-
-6) then name your character in the Title then close the text block.  Finished
-
-no more need to create character sheets!  That simple and any time you want to see it, just doubleclick on the text node.</nodehandler>
-  </nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 4: Setting up rooms/games and Ignore">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="There's a party going on down my street tonight...">&lt;a name=&quot;c4&quot;&gt;&lt;/a&gt;
-now that you have your custom built char sheet and you have talked enough players into starting a game, it's time to set up your own room.  Let's bring up that Tracker window again ((under the Game Server menu)).  Looking to the bottom left of it, you'll see a little box that allows you to type in your own room name and add a password if you like.  Let's start a room called &quot;Working on that darned fun tutorial&quot; and not put a password up.
-
-as you see the room you create will be exactly the same as the lobby, so there is nothing to worry about.  Lets load up our character sheet by right clicking on the &quot;Game Tree&quot; and pressing Insert file&quot;
-
-Now that we have our little char sheet we might as well show the world.  This can be done in one of three ways.  The first way is to right click on it and send it to other players (provided there are any).  This is how other players can get your sheet as they can't see it until you send it to them.
-
-The second way is to send it directly to the chat and let everyone see it there.  go ahead and do that by right clicking on the char sheet and pressing &quot;Send to Chat&quot;.  Now everyone gets to see it as it appears on their text chat window.
-
-the third option, Whisper to Player, is much the same as &quot;Send to chat&quot; only it sends it to a specific person or persons to see in their chat instead.
-
-Of course, there sometimes comes a day when there is a little spammonkey running about.  You know the type.  Just keeps askin pointless questions, hitting you with the same text, and generally making himself a nuesance.  Well fear not!  We have added in a brand new feature that allows you to ignore those unscrupulous people.  In the chat entry box just enter the command &quot;/i player_ID#&quot; and that will put a person on ignore (or toggle them back to un-ignore).  To get a list of ID's who are on your ignore list, just type &quot;/i&quot; alone, with nothing else.  You can even ignore/un-ignore multiple people at once, just put commas (( , )) between the names.  And that's it.  Ignore at your leasure.</nodehandler>
-  </nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 5: Maps and Minis">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="So you had to ask...">&lt;a name=&quot;c5&quot;&gt;&lt;/a&gt;
-Now comes the hardest part of the tutorial.. describing how to use minis and pictures.  Well, the first step is to bring up the map.  With any luck it is still open so let's find it.  It'll be the big green one that was in the top right of the screen.  If it's not there, click on the &quot;Windows&quot; menu under the OpenRPG main window and press &quot;Map Window&quot;.
-
-&lt;/center&gt;**note!** If you are in the lobby, the changes you make to the map will not be seen by other players.  You will need to create another room to have a shared map.&lt;/center&gt;
-
-In this map window you'll see all of the basic operations needed to load an image and edit the map.  Let us attempt to load our first picture.  At the bottom of the map window you'll see a large box where you can type in text.  This is where you put  the Webpage Address for the image you wish.  Let's type in this addy.
-
-http://www.openrpg.com/images/mins/amazon.gif
-
-after you have typed it in press the &quot;add minature&quot; button, sit back, and watch as it loads the beautiful amazonian woman (well, almost) into the map folder
-
-&lt;center&gt;&lt;b&gt;&lt;u&gt;OpenRPG tip:&lt;/u&gt;&lt;/b&gt; All images need to be on webpages... you cannot load directly from your hard drive.  The reason being this is actually one giant web browser.&lt;/center&gt;
-
-Feel free to move it about, get a feel for how it works.  You'll see at the moment that the amazon seems to hop from grid square to grid square.  Well... if you're like me, you don't like being confined to grids or rules.  So let's get rid of that grid, shall we?
-
-Looking at the map window again, you will see a little red diamond thing.  They say it is a compass but it just looks like a flying fish to me.  Anyway.. click on that and it will bring up all the map settings.  In there you can change the size of the map, what colour it is, or even load up a background on which all the mini's sit ((say, a dungeon map you drew or perhaps that picture of Britney Spears I know you have lying around)).  The thing we are interested the most, though, will be the grid settings at the bottom.  As you can see, you can change the size of the grid and switch the grid from square(4 sided) to hex (6 sided).  You'll also be able to let mini's either abide by the grid, or become free from the black lined prison.  Let us turn off the grid snap and press &quot;apply.&quot;
-
-Now, go back into the map window and try moving your mini again.  You'll see that it now moves freely, and ignores those lines.  But ignoring them is not enough, did I hear you say?  You want them gone?  Ok.  Let's go back into the settings (the red star button) and this time change the grid size to zero.  Pressing 'apply' you will see that the grid has disappeared entirely from map.  Course, if you want it back, just go put in the size again (50 is default).
-
-There are other options (like direction pointing for your mini's) so feel free to play around a bit.
-
-&lt;center&gt;&lt;b&gt;&lt;u&gt;Note:&lt;/u&gt;&lt;/b&gt; you can find many great mini's on the OpenRPG webpage.&lt;/center&gt;</nodehandler>
-    <nodehandler class="link_handler" icon="html" module="core" name="&lt;center&gt;www.OpenRPG.com&lt;/center&gt;">
-      <link href="http://www.OpenRPG.com"/>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="static_handler" module="core" name="Chapter 6: Make your fortune in Server Control!">
-    <group_atts border="1" cols="1"/>
-    <nodehandler class="text_handler" icon="note" module="core" name="&lt;b&gt;Well, maybe not any money...&lt;/b&gt;">&lt;a name=&quot;c6&quot;&gt;&lt;/a&gt;
-Well, maybe not any money in creating a server on this program, but there are definately perks to running one.  But to run one we must first understand what they do.
-
-A server is the mother for all of us on OpenRPG.  It runs all of our major commmands, keeps us all talking together, and hosts all the games on OpenRPG.  When you first connected to OpenRPG you had to choose a server from a list in the tracker, on the left.  Now let us put your name (or at least your computer's) out there so others can flock to you.
-
-For this we must return to your OS.  Go into your computer, into the OpenRPG folder.  In there, you will see a file marked:
-
-mplay_server.py
-
-You can also find it in your start menu, right next to the OpenRPG program itself.  Once you find it, (double)click on it.  The first thing that will come up is a python MSDOS window... It will first prompt on if you wish for your server to bee seen by the OpenRPG tracker list.  Press &quot;Y&quot; and hit enter (won't get anyone if we don't know it exists).  Next, it will prompt you for a name for your Server.  Write in &quot;Temporary Server&quot; and press enter.
-
-Now the window will start running the various server-y looking bits of code.  as soon as it is up and going, you will told the various commands that are available to the server.  The first one will be &quot;kill&quot;.  this is what you type into the MSDOS window to shut the server down.  &lt;b&gt;**IMPORTANT**&lt;/b&gt; if you shut down the server all rooms on it will close.  You don't want to shut it down if others are using it.
-
-The second command is the &quot;dump&quot; command.  This will list all the people on your server, as well as their ID number.  It really isn't important at this time but it will come in handy later.
-
-Broadcast is self explanitory.  The 'Announce' and 'Remove' features allow you to choose later on if your server can be seen on the tracker, or not.  Dump Groups gets the same info as Dump but does Groups instead of people.  And finally you can bring up this little list of commands at any time by typing 'help' or '?'.
-
-You can type these commands in any time in the python server window.  Go ahead and try 'help' or 'dump' and see what comes up.
-
-Alright!  That's it.  to access your server, run you OpenRPG program as normal (with the server MSDOS window in the background) and log onto your server as we had shown you in chapter 1.  This will come in handy if there are no Servers running and you wish to use OpenRPG with, perhaps your gaming buddies or maybe some underworld kingpins you need to 'have a talk' with.
-
-And From All of us at OpenRPG HQ, we wish you good gaming!</nodehandler>
-  </nodehandler>
-</nodehandler>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/templates/nodes/Traipse_User_Guide.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -0,0 +1,265 @@
+<nodehandler class="tabber_handler" frame="636,449,368,80" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
+  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
+
+This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
+
+What is OpenRPG:
+OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
+
+What is Traipse OpenRPG:
+Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
+
+Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.
+
+The User Manual:
+The user manual is divided into Chapters and Sections.  Each Chapter will go over the various features of OpenRPG and attempt to explain them in an easy to understand format.
+
+Adding to the Manual:
+Do you see something that could be explained eaiser?  Report the problem as a bug and it will be added to the manual.</text>
+</nodehandler><nodehandler class="tabber_handler" icon="player" map="Traipse OpenRPG::User Manual" module="containers" name="Chat" version="1.0"><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual::Chat" module="forms" name="Using Chat" version="1.0">
+  <text multiline="1" send_button="0">The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few.
+
+The chat includes a set of commands. You can learn about the commands by entering /help
+
+The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text.</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="ccmap" map="Traipse OpenRPG::User Manual" module="containers" name="Map" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::Map" module="forms" name="Using The Map" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
+The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
+
+When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
+
+Lurker or in the Lobby: 
+You cannot access any map tab or changes it's settings.
+
+Player: 
+You have access to the Miniatures tab and the Whiteboard tab.
+
+GM: 
+You have access to all of the tabs.
+
+The Layers:
+A small description of each of the layers.
+
+Background: 
+You can set an image as the background, an image as a tile, or you can set a color.
+
+Grid: 
+You can change the grid size, lines, turn off the grid snap, and change the grid shape.
+
+Miniatures: 
+You can add new or remove miniatures and change mini properties and labels.
+
+Whiteboard: 
+With the whiteboard you can draw lines or add text to the map.
+
+Fog: 
+The fog layer hides the entire map from the prying eyes of players.
+</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="gear" map="Traipse OpenRPG::User Manual" module="containers" name="Game Tree" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual::Game Tree" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Quick Help" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">Quick Help:
+
+The referencing system is an update to the Core of how the Game Tree works.  In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further
+
+A.
+Think of the Game Tree has a folder on your hard drive. Each :: inside the reference syntax works just like a system separator (/ or \)
+
+B.
+Root References start at the tree itself. If the node being referenced changes location the reference will be invalid.
+
+C.
+Child References work at the location of the node containing the reference. 
+
+Example: 
+Game Tree
+- Group
+-- Text Node
+--- Group_2
+---- Text Node_2
+--- Group_3
+---- Text Node_3
+
+In the above Tree example you can reference Text Node_2 with a root reference
+
+!@Group::Group_2::Text Node_2@!
+
+or you can use a Child Reference from within Text Node
+
+!!Group_2::Text Node_2!!
+
+D.
+Parent References work with the Tree Map. Unlike Child references that look only at the current nodes location, Parent References are allowed to travel backwards in the gametree. 
+
+Using the above example, you could reference Text Node from Text Node_2 with the syntax: !#Group::Text Node#!
+
+Parent References have a special power in that they need only a certain amount of data for the software to understand them. In the above example you could reference Text Node_3 from Text Node_2 with only this syntax !#Group_3::Text Node_3#!
+
+The reference system is still a bit primitive in it's implementation.  As I was saying it is an advancement to the Core technology of Traipse OpenRPG.
+
+While it is confusing at first, the model is far superior to other tree referencing systems.  Pre 1.8.0, no node could reference a Grid. The referencing system required the reference to be exact and started at the root. Also, the new model is designed to enable freedom of creation and greater control over the Game Tree.
+
+With the Traipse Game Tree GMs are enabled to reference any data from the Game Tree, no matter where it stands. Players can create fewer nodes and use more of the data with fewer nodes.
+
+EZ_Tree (One Touch Reference):
+(ALPHA!)
+The new EZ_Tree System will help benefit users who do not understand the syntax, nor care to learn.
+
+The EZ_Tree System works from within Lists, Texts, and Grids. In the Design Panel you can push the Reference button and navigate the small gametree that pops up to the node you want. Double click that node and the software will create the most efficient node reference for you.
+
+(ALPHA!) In it's Alpha state, Grids will not work completely. You can reference a grid, but you must add teh cell reference. That is not a design flaw, but a restriction of time constraints.
+
+Developer Note:
+The syntax is the hardest part to understand and I expect to change that in the future. The Core of a more expansive Game Tree model is designed. In Traipse you do not need to give access permissions to a node in order to reference it's entirety, which is what I see with Index and Namespace from OpenRPG Core.
+
+In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location.
+
+This freedom will help with future design and I feel it also frees up the hands of the GM who does not need to Index, un-Index, Namespace, un-Namspace the various creatures he or she may have in a Game Tree.</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Root Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
+Works at the tree level. Must be exact.
+
+&lt;b&gt;Root Reference 1:&lt;/b&gt; !@Reference Examples::Group::Child@!
+&lt;b&gt;Root Reference 2:&lt;/b&gt; !@Reference Examples::Grid::(2,1)@!</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="441,400,514,48" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Grid Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Grid Reference&lt;/b&gt;
+Works by looking at the (Row, Column) of a Grid.
+
+&lt;b&gt;Grid Reference 1:&lt;/b&gt; !@Reference Examples::Grid::(1,1)@!
+&lt;b&gt;Grid Reference 2:&lt;/b&gt; !!Grid::(1,1)!!</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,517,63" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Child Reference" version="1.0">
+  <text hide_title="1" multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Child Reference&lt;/b&gt;
+Works at the current tree location.
+
+&lt;b&gt;Child Reference 1:&lt;/b&gt; !!Group::Child!!
+&lt;b&gt;Child Reference 2:&lt;/b&gt; !!Group::Group_2::Child_2!!
+</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="forms" name="Parent Reference" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Parent Reference&lt;/b&gt;
+Works by indexing the tree map of the node with the Reference. Allows you to start from a 'Parent'.
+
+&lt;b&gt;Parent Reference 1:&lt;/b&gt; !!Group::Group_2::Child_2!!
+&lt;b&gt;Parent Reference 2:&lt;/b&gt; !#Bonus Nodes::Deck::Draw#!</text>
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="containers" name="Group" version="1.0">
+  <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group" module="containers" name="Group_2" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2" module="forms" name="Child_2" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
+  <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
+</nodehandler></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples::Group" module="forms" name="Child" version="1.0">
+  <text multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Game Tree::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell size="147">0</cell>
+      <cell>0</cell>
+    </row>
+    <row version="1.0">
+      <cell>!!Group::Child!!</cell>
+      <cell>0</cell>
+    </row>
+  </grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual::Game Tree" module="forms" name="Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
+
+Grid Nodes:
+  Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@!
+The example will return the top left most cell data. The grid understands coordinates like this (Row, Column)
+
+  Grid nodes can reference node data just like any other node can.  With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll.  While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. 
+
+  Here is an example with a 3 x 3 Grid
+Example: !@Grid::([#1d3], [#1d3])@!
+
+The result will be a random event from the grid.
+
+Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52)
+
+List Nodes:
+  List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node.
+
+  For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references.
+
+(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.)
+
+  Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!!
+
+Text Nodes:
+  Text nodes remain little changed.  I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes.
+
+  Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes.
+
+  Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
+
+Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual::Game Tree" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
+
+(Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map)
+
+Reference Types:
+  There are three ways of references node data. A Root Reference, a Child Reference, and a Parent Reference.
+
+Root Reference: 
+  A node reference that starts at the Game Tree. The location of the node must be exact or you will return an Invalid Reference!
+
+A Root Reference uses this syntax:
+!@Node::Child::Data@!
+
+Child Reference: 
+  A node reference syntax that starts by looking at within the current container node. As long as the Child Reference is in the same container as the node, the container can change location and the reference will not be damaged. Child References work from within a PC Sheet node as well.
+
+A Child Reference uses this syntax:
+!!Node::Child::Data!!
+
+Parent Reference:
+  A node reference syntax that starts by looking at the tree map and the reference used, then makes an addendum to the node's map to create a reference.  The Parent Node is used when you want to reference the data in a node that is within a different child container of the same parent node. 
+
+A Parent Reference uses this syntax:
+!#Node::Child::Data#!
+
+Syntax for Special PC Sheet Nodes:
+  The nodes for the specialized PC Sheets now have a new syntax.
+
+Skills, Saves, and Abilities:
+  Skills, Saves, and Abilities all have a similar referencing syntax.  You can return the base value of each by using the correct syntax.
+
+Examples:
+!@Jonethan::Skill::Jump@! (Returns Jump ranks)
+!@Mikael::Strength@! (Returns Ability Score and Mod)
+!@Draj::Will@! (Returns Will Save and Mod)
+
+(Saves and Abilities have a short hand and a long hand. Abilities can use the three letter abbreviation, while saves short hand are Fort, Ref, and Will)
+
+  You can append Check to check each of these against a 1d20 roll, or you can append Mod to discover the Modifier. The Mod can be useful in other nodes
+
+Combat:
+  You can now reference your attacks easily with the Game Tree.  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.
+
+Powers, Spells and Feats:
+  Power, Spells and Feats are hard to sometimes hard to remember, and even harder to code.  The use of the Power, Spell or Feat syntax serves as an emote of what you are doing, as well as a reminder of what your Power, Spell, or Feat does.
+
+Examples: 
+!@Kammen-Pai::Cast::Ray of Frost@!
+!@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler></nodehandler><nodehandler class="tabber_handler" icon="labtop" map="Traipse OpenRPG::User Manual" module="containers" name="The Server" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual::The Server" module="forms" name="Setting up a Server" version="1.0">
+  <text multiline="1" send_button="0">In Traipse starting a server has never been easier.  The setup is as easy as 1., 2., 3
+
+1. You will need to first start the Server GUI or the basic text based Server at least once so your software creates the server_ini.xml files in your myfiles directory. You can start it once and quit.
+
+2. Edit the server_ini.xml file. Here you can set the server's name, the boot password, and even set the servers port.
+
+Traipse allows you to specify a server port instead of the software demanding port 6774.
+
+3. This is the hardest step. You need to make sure your selected port is forwarded by your router and open to your firewall.
+
+That's it! You can now start the server and register it to the meta for all users to enjoy!</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,0,48" icon="browser" map="Traipse OpenRPG::User Manual" module="containers" name="Links" version="1.0"><nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Release Notes" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse" />
+  </nodehandler>
+  <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::User Manual::Links" module="forms" name="Traipse User Guide" version="1.0">
+    <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
+  </nodehandler>
+  </nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/templates/nodes/Userguide098.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-
-<nodehandler class="tabber_handler" icon="book" module="containers" name="User's Guide to OpenRPG 0.9.8" status="useful" version="1.0">
-  <nodehandler class="textctrl_handler" icon="note" module="forms" name="Introduction" version="1.0">
-    <text multiline="1" send_button="0">Welcome to the online gaming universe of the OpenRPG!  By now you have successfully downloaded and installed the program or you would not be able to read this document.  But we are not here to discuss what you already know, but to tell you how to do those things you don't know.
-
-What we'll cover in this guide:
-1)How to use the basic OpenRPG
-2)How to do those really nifty advanced things in OpenRPG
-3)How to get your brother to do those nifty things in OpenRPG while you beat him with a whip
-4)Getting along with those others on the OpenRPG program
-
-And, before long, before you know it, and before that chicken in the microwave is done, you will know and have mastered the art of using OpenRPG.</text>
-  </nodehandler>
-  <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Guide Chapters" version="1.0">
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Art Of The Chat" version="1.0">
-      <text multiline="1" send_button="0">The basics:
-
-Alright.  Let us start at the beginning.  Many many years ago the dinosaurs roamed the planet.  But then an asteroid, now most commonly known as &quot;Bill Gates 1,&quot; crashed into the earth and wiped them all out, turning them into oil.  The basic upshot of all that is with this oil we have created electricity which is now running the program.
-
-Before we start it is necessary to make a name for yourself.  Why?  Well, you wouldn't like to be going around with everybody knowing only as 'blankman' would you?  To type in your name, go up to the top left window, and dragging down the &quot;OpenRPG&quot; menu bar press &quot;Settings&quot;.  in there you can alter your name and colours.
-
-You can also rename yourself in a much more simple way by typing in the command &quot;/name &quot; and your name behind it in the chat window.  I just made you go into the settings so that you know where they are later.
-
---------------------------------------------------------------------------------
-
-Now that you have yourself labled, you are probably wondering &quot;where's all the chat?&quot;  Well, my friend, we are here to answer that.  As your program booted up, it should have brought up a four-window layout.  The Gametree Window is in the top-left, the Player Window is the bottom-left, The Chat Window is the bottom-right, and the Map Window is the top-right.  We will first concern outselves with getting that lower right window to do the work and play with the others later.
-
-To get the chat window to work, first we actually need a place to chat.  To do this, we need to browse the list of rooms on what is known as the Tracker.  To open the tracker window go to the menubar on the top and under the menu &quot;Game Server&quot; click on &quot;Browse Tracker&quot;
-
-As you can see, a new window popped up.   This is the Tracker Window.  On the left you will see a list of various servers running OpenRPG online.  Click on the one at the top of the list and press &quot;Connect&quot;.
-
-After pressing the &quot;Connect&quot; button you will join that server and be instantly dropped into it's lobby.  Welcome to your first chatroom.  Feel free to stay in this room as long as you like or move off to another room listed on the Tracker.  When you first turned on OpenRPG the chat window filled up with all the different chat commands available.  If you are like me and have forgotten them by now you can either click on the text display box and press PageUp   or click on the little text entry box and type in &quot;/help&quot;.
-
-Should you wish a way to scroll up instead of 'PageUp'ing you can increase the amount of lines the Chat Window stores by making the Buffer Size larger.  You can do this by changing the &quot;buffersize&quot; setting in the Settings menu or by using /lines [number] replacing [number] with the number of lines..  A good setting is 100-200 lines though you can have it as large as you want (though it is warned against having it larger than 1000 as large numbers tend to increase lag.)
-
-------------------------------------------------------------------------------
-
-By now I'm sure you are also wondering what that status thingy in the bottom left window is.  If you notice, every time you type a message in the chat window your status changes.  And when you finish your msg (or sit for 5 seconds waiting) it changes back to Idle.  What a clever invention.  Of course, if you wish to set your own status to override &quot;Idle&quot; temporarily, just type in the chat window &quot;/status My_Status&quot;; replacing &quot;My_Status&quot; for whatever msg you wish (no more than 18 letters can be seen though).
-
-As for now, spend some time and enjoy yourself in the lobby... we can come back to the tutorial when you are ready to learn about Rolling dice, whispering, and creating and using character sheets.</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Rolling Dice" version="1.0">
-      <text multiline="1" send_button="0">Dice:
-
-there are two methods of rolling dice.  The first way is very simple: press the bottons on the dice toolbar.  The only explination there is on the left there is a box saying how many dice to roll, and on the right there is a box for modifiers.
-
-The second way is a little more advanced, and powerful.  You can also roll dice by typing them into your text intry box under the dice toolbar (where you type your normal chat messages).  to do so, first choose how many dice you want to roll.  example:
-
-1
-
-now, put the letter &quot;d&quot; after that.
-
-1d
-
-then put the dice type (number of sides):
-
-1d20
-
-And to finish it off, put the square [ ] brackets around the dice and hit enter
-
-[1d20]
-
-you'll see it rolls a dice into the chat window.  Magic. we can even do things like having multiple types of dice inside it in various mathmatical combinations:
-
-[1d20+4d6-12]
-[3d8+2]
-[1d1-1]
-
-
-------------------------------------------------------------------------
-
- now we let the fun begin.  Inside the square brackets we can also add special modifiers.  it'll come in the following format:
-
-[ 1d20.mod(#) ]
-
-you can even have multiple modifiers if you wish.  the list of all of them are below:
-
-.ascending()
-lists your dicerolls from lowest to highest
-
-.descending()
-lists your dicerolls from highest to lowest
-
-.takeHighest(#)
-takes the highest # amount of rolls
-
-.takeLowest(#)
-takes the lowest # amount of rolls
-
-.extra(#)
-rolls 1 extra dice for every Original roll that gets above the #
-
-.open(#)
-rolls an extra dice for Every roll that gets above the #
-
-.minroll(#)
-no dice will roll below #
-
-.each(#)
-adds # to each diceroll
-</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Whispering and Ignoring" version="1.0">
-      <text multiline="1" send_button="0">Of course, not everything should be heard.  This is true twice over in this chapter, as we will be discussing how to whisper and how to ignore.
-
-Whispering is a very simple task in OpenRPG.  First type in &quot;/w &quot; in the text entry box.  next, type in the ID number of the person you wish to whisper to and add an equals sign, so it looks like this:  &quot;/w 4=&quot;.  Add your message to the end of that and hit enter.
-
-/w 4=Hello ID number 4.
-
-You can even have multiple ID numbers in there.   Just seperate them up with a comma between each one, like so:
-
-/w 3, 4, 12=Hey, I dare you to poke that Woody
-
-Of course, if you don't want to type out the weird ID numbers you can always just right click on those little Easter Island Heads next to the person's name in the bottom left player window.  You can then select &quot;whisper&quot; and it will put the whisper command into your text entry box automatically.
-
--------------------------------------------------------------------------------
-
-Sometimes there is someone that will just really get on your nerves.  Be it that they keep sending the same line of text to the chat, or maybe that they are spouting out Britney Spears lyrics nonstop.  Either way, you'll probably want to hear less of them.
-
-Well fear not!  for by just typing in &quot;/i their_ID_#&quot; (changing &quot;their_ID_#&quot; for their ID number) and hitting Enter, then they will be added to your ignore list and no further messages will be heard by them.  Should you wish to take them off again (in case you go the wrong guy) just type the same thing and it'll toggle it off.  You can also get a list of who's on your ignore list just by typing in &quot;/i&quot;
-
-Simple as that.</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Create Your Own Character" version="1.0">
-      <text multiline="1" send_button="0">((before we begin, see the character sheet repository:
-   http://openrpg.wrathof.com
-for pre-made character sheets.))
-
-
-Character Sheet creation (By Melanthos):
-
-So you wanna make a character sheet, huh? Well, follow these few short steps and you'll be on your way to Sheet Creation Godhood...or not. But don't blame me if you don't read this and can't make yourself a sheet. I'm going to guess you have a basic understanding of how the nodes work. I'll be using Harvester Incorporated(TM)'s Faction Wars(TM) as an example.
-
-First, you'll need a tabber. You can find it under containers in the templates node.  Click the + to the left of templates then click the plus next to containers.  Next double click the Create New Tabber.  Got it? Good. Now, you'll need a form. Forms are what we use to create each page of the tabber. They hold the rest of the nodes neatly, and open up - unlike groups, which cannot be opened in a sheet. To create a form double click on Create New Form.  You will notice two new nodes at the top of the game tree.
-
-
-        Tabbers, Forms, and Text-boxes, OH MY!
-
-Alright. Here is where I store the basics of the character. Since I don't like to scroll too much, I've broken down the information even more, so that I can fit into smaller tabbers and forms. First I'll create a second tabber. This will hold all the basic info - Level, Class, Player &amp; Character name, and a few other things. Since I've got 8 things I want to list, I've broken them up into 2 seperate groups, which have been put into different forms: General Info, and Specific Info. For simple things like name and level, I suggest using single-line text boxes. I've gone ahead and made 8 of these, naming each of them one of my 8 items and stuck them into their forms. Now that I've finished that, I'll put the two forms under my second tabber, and put that into my big form, &quot;General.&quot; I've done the same thing with the Attributes. Most of the sheet uses this principal, so I won't go into each form. Kinda redundant.
-
-
-                   List Boxes &amp; Die Creation
-
-Alright, for my second form, Vitals, I need some die-rollers. Since I don't need to change the rolls often, I've decided to use List Boxes to hold all my rolls. It's not too hard, and it's a really easy way to store rolls(It can be used for other things, but this is the best use I've found.): Now you don't have to type out those dice every time you wanna attack. First, I've created myself a List Box. Next, I'll decide how I want my list box to be shown: There are four choices. Drop Down, List Box, Radio Box, and Check List. Since I only need to roll one at a time, I've chosen Drop Down. But to show you how the Drop Down and Check List options work, I'll change things a bit and make a List Box and a Check List as well. When editing, make sure to click the &quot;Send Button&quot; box.
-
-
-        Drop Down
-
-The Drop Down is the least space- consuming of the List Box options. It's just like a single-line Text Box, except it holds more than one line. Click the arrow on the right to make it drop down, and click the die you want to roll. Then hit the Send button, and POOF! Your die has been rolled to the chat window.
-
-
-        Check List
-
-The Check List is a neat option. It lets you roll more than one die at a time. All you have to do is check the box next to the die (or dice) you want to roll, and POOF! Your dice have been rolled. Neat, eh?
-
-           Splitter
-
-Now what could these be used for, you wonder? Not much, but there are a few things. I've used it to hold my different abilities. It's easier for me to just see my choices than to flip between tabbers or scroll down and back up every few seconds.
-
-
-The rest is pretty easy. Just keep on with the things you've done so far, and in no time you'll be on your way to creating great sheets! Most of sheet creation is your personal preference. If you ask Woody, he might say something completely different than I might. Of course, you should make the sheets the way you want them. This is just to get you started. After you've got the basics of sheet making down, you can play around with sheets and nodes and things until you've got the sheet perfect for you. GOOD LUCK!!
-
-
---Melanthos, Founder &amp; Game Designer - Harvester Incorporated</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Running Your Own Server" version="1.0">
-      <text multiline="1" send_button="0">Creating a server:
-
-OpenRPG has come a long way since the dark ages of gaming.  With this new version we can now create servers on-the-fly!  No more black boxes or strange voodoo magic.  Just click on your &quot;Game Server&quot; menu, and select &quot;Start new server.&quot;  Fill in the options and away you go!  the server will appear instantly on the list.
-
-Of course, this won't provide you with all the same powers that the full server does.  While you can create a server on the short term, if you want to have a longterm dedicated server running which you can control, you'll want to run the OpenRPG Server in your start menu-programs-openrpg (or mplay_server.py in your openrpg folder).
-
--------------------------------------------------------------------
-
-So now that you have your server, your custom character sheet, and have talked enough players into starting a game, you'll want to set up a private room so that you aren't disturbed by every wandering weirdo or Woody that happens upon your server (and be forwarned, you will find that various people will wander from server to server.  Do not be frightened, most of them are harmless).
-
-So, lets pull up your tracker window.  If you haven't done so already, be sure to connect to your server.  Once in there look onto the right side of the tracker window.  You will see some boxes marked &quot;Room name&quot;, &quot;Boot password&quot;, and if you check a little box, &quot;password&quot;.  the first two are rather self explanatory, and the last one is to lock your room in case you don't want to be bothered.  Be sure to tell your players what it is though.
-
-If you don't password protect a room you may get people wandering in looking for a game or just lurking watching your game.  If you don't want them in there you should first let them know and ask them to leave.  If they refuse your request then boot them.  It is very rude to boot someone from a non passworded room with out warning.
-</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Of Maps and Miniatures" version="1.0">
-      <text multiline="1" send_button="0">The Map:
-
-Now comes the hardest part of the tutorial.. describing how to use miniatures (minis)  and background images.  Well, the first step is to bring up the map.  Fortunately the new OpenRPG now loads maps differently than previous versions.  Likewise, it no longer seems to cause crashes for Windows users.  No longer will your client lag, lock up, or crash when loading images, large or small.  The entire map will now load in the background while you continue with your normal activity with the program.  Additionally, images, once loaded, will also be cached (stored) in RAM (up to 64; overflow is handled by randomly purging images within the cache to make room for new images).  That means switching back and forth between maps, in the same session, will result in instantaneous access to your map; no more waiting.  Furthermore, not only are your images loaded in the background, but they are loaded concurrently.  That means your map will be available faster than ever!  Hopefully these new innovations will lead to a renewed usage of the map.  Even modem users have indicated that using maps are now fun again!  Anyway, on with the tutorial.
-
-The Map Window is where most of your image viewing will reside.  In it you can manipulate miniatures and maps to give your players a well good idea of what your gaming world looks like.  In case you haven't guessed, it's the top-right window.  Looking at the Map Window, you'll see all of the basic operations needed to load an image and edit the map.  Let us attempt to load our first picture.  At the bottom of the map window you'll see a large box where you can type in text.  This is where you put  the Web-page Address for the image you wish.  Let's type in this URL/URI:  http://www.openrpg.com/images/mins/amazon.gif.  Notice that there are many great miniatures ready for you to use at OpenRPG's home-page.
-
-After you have typed it in press the &quot;add miniature&quot; button, sit back, and watch as it loads the beautiful amazonian woman (well, almost) into the map window.  Please note, however, all images need to be on web-pages and served up by a web server... you cannot load directly from your hard drive.  Well, you can, but no one else will be able to see it.  The reason being is because OpenRPG's client actually one giant web browser.
-
-Feel free to move it about, get a feel for how it works.  You'll see at the moment that the amazon seems to hop from grid square to grid square.  Well... if you're like me, you don't like being confined to grids or rules.  So let's get rid of that grid, shall we?  Again, looking at the map window, you will see a little red diamond thing.  They say it is a compass but it just looks like a flying fish to me.  Anyway.. click on that and it will bring up all the map settings.  In there you can change the size of the map, what color it is, or even load up a background on which all the mini's sit ((say, a dungeon map you drew or perhaps that picture of Britney Spears I know you have lying around)).  The thing we are interested in the most, though, will be the grid settings at the bottom.  As you can see, you can change the size of the grid and switch the grid from square(4 sided) to hex (6 sided).  You'll also be able to let mini's either abide by the grid, or become free from the black lined prison.  Let us turn off the &quot;snap to grid&quot; and press &quot;apply&quot;.  Also note that you can also make the grids disappear by making them match the background color, however, this is not the ideal way to do it as it still requires processing to draw and redraw the grid lines, even if they blend in without being visible.
-
-Now, go back into the map window and try moving your mini again.  You'll see that it now moves freely, and ignores those lines.  But ignoring them is not enough, did I hear you say?  You want them gone?  Ok.  Let's go back into the settings (the red star button) and this time change the grid size to zero.  Pressing 'apply' you will see that the grid has disappeared entirely from map.  Course, if you want it back, just go put in the size again (50 is default).  Feel free to make the grid size match your miniature and map scale.  Also, if you prefer to have the snap to grid, however, do not feel that it provides enough resolution in miniature movement, feel free to set the grid size to half or one forth of what your actual scale is.  This way, you miniatures will still fit nicely as well as be able to use the &quot;snap to grid&quot;, however, you'll better be able to stagger your miniatures or slightly offset tiled map sets.
-
-
-Tiled Map Sets:
-
-Often, DM's and GM's have the need to present a map to their players, however, they do not which to reveal the whole map and/or map section to their players.  After all, it does remove a lot of surprise if everything is right before the player's eyes.  Enter three new miniature options: &quot;Lock to back&quot;, &quot;Lock to front&quot;, &quot;Unlock Front/Back&quot;.  Previous to these options being available, either the whole map had to be loaded by changing the background image or players and DM's where forced to struggle when map sections were loaded as if they were miniatures.  Even though there was z-ordering options available, it was still tedious as miniatures would often disappear behind a map image.  Now, entire maps can be built before as game and loaded all at once, without giving away any surprises.
-
-By loading all of your map sections together as miniatures and marking each one visible or not visible, you can have great fun again with your maps!  Wait a minute, isn't this the same boat we were on before.  Well, enter the three new options.  Using the &quot;Lock to back&quot; option on each of your map sections, it will force them to always stay on the bottom of the z-order (stacking) of your miniatures.  That means, you'll now be able to change the z-order of your miniatures while all of them stay on top of your map image.  In other words, while the image is locked to the back of the z-order, it acts just like a background image should.  To restore a miniature to normal z-ordering, simply using the &quot;Unlock Front/Back&quot; option and it will once again be ordered just as any other miniature is.
-
-Wait a minute!  That's only two of the three options that you mentioned.  Well, the third option allows for even more flexibility in what DM's and GM's can present to their players, even on a visible map section.  Enter, the poor-man's fog-of-war.  By creating a &quot;mask&quot; in just about any shape you like (feel free to use transparent colors on gifs as needed), you can effectively lock the &quot;masking&quot; image to the top of the z-order which will hide a section of your visible map.  While this is still somewhat tedious, it will allow for much finer grain of control of what is and is not visible on your maps!
-
-
-Looking here, moving there:
-
-Directional markers have been a part of OpenRPG for some time now, however, there use is going to be better explained here.  If you notice, each miniature has a &quot;facing&quot; and &quot;heading&quot; available to it.  These serves not only to indicate a miniature's facing, but it's current direction of travel.  After all, you're quite able to turn your head and talk to your buddy while walking in a direction different than the one your head is pointed.  While this feature mostly serves board game players, RPGer's may find use in this too, especially when making canned maps.  Imagine, the 'ol evil cleric behind the podium with his back to you.  Now, you can make it clear on the map.  Oh wait, the cleric's minions do not have their back to you, rather, they are standing to his side and looking directly at him.  Closer look, and you see that the cleric too had his head turned to his minions in conversation.  Again, this can be expressed on your map.  Information like this makes it easier for the players to understand that the back-stab that they obviously want to do, won't be so easy to pull off.  All this, without having to verbally describe every little detail.  After all, isn't this what the maps is for?  Enjoy!
-
-
-Saving and Loading Your Map:
-
-Don't forget that you can save your hard work.  Once you have built your map, be sure to right click on the map and hit &quot;Save Map&quot;.  When you need it again, just do &quot;Load Map&quot;.  You don't even need to delete the contents of the previous map.  The client does all that for you!  Don't forget, if you load a previously viewed image, the caching will considerable speed the rate at which it's visible to you and your players.  Using a common set of miniatures helps to take advantage of this fact.
-</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Other Features; Logs, Initiative, Upgrades" version="1.0">
-      <text multiline="1" send_button="0">Other features:
-
-It may seem a little odd that this seventh window is tucked behind some arrows, but I always thought this chapter was a little on the sinful side so over here it now lay.
-
-
-By getting here, you must have had quite a bit of time to read through the rest of the chapters.  Well, let's finish off with what few interesting toys we have left.
-
-To start with, lets talk about logging  To create a logfile, you can just press the disk button in the bottom right corner of the OpenRPG program, and choosing a name and place to save the file.  Badaboom!  a chatlog of everything you have seen is saved.
-
-Of course, most of you will want a way to have it automatically save a log each time it see's text.  To do that, type in &quot;/log to my_log&quot; (replacing &quot;my_log&quot; for what you want to call the file). It should automatically start logging to that filename (and will include the date in the filename you gave it).  if you want to turn it on or off later on, just type &quot;/log on&quot; or &quot;/log off&quot;
-
-Note: The chat logging system no longer appends a datestamp to the logfile
-specified.  This means that for the system to generate the logfile
-
-/foo/bar/gamelog-02-10-01.html for linux or \foo\bar\gamelog-02-10-01.html for windows
-
-Previously the user only had to have &quot;/foo/bar/gamelog&quot; entered as GameLogChatPrefix.
-To get the same logging pattern now, they'll have to set GameLogChatPrefix to
-the following:
-
-/foo/bar/gamelog-%d-%m-%y.html
-
-
---------------------------------------------------------------------------------
-
-The Initiative Tool.  A marvelous invention allowing DMs to organise and handle an otherwise chaotic scene that we know as combat.  Compatable with all versions of OpenRPG, it works incredibly simply.
-
-All that is needed is for the DM to press &quot;New Initiative&quot; in the tool, have all of the players and the DM to type in &quot;init [diceroll]&quot; (replacing 'diceroll' for your dice) and hit enter.  An example:
-
-init [1d10+6]
-
-once everyone has done that, the DM pulls up his tool again, hits refresh, and then sorts the list however he wants.  once it is sorted, he just hits &quot;send to chat&quot; and the person at the top of the list is then sent to the chat.
-
-Once all the people have been cycled through, it will say &quot;End of Init&quot; in the chat.  The DM just presses the &quot;Start new Initiative&quot; button one more time and away you go on another round of hacking!
-
-Now, if you are the player and not using the tool, you can even put your init command into a macro node (not a text node) and do it that way.  At the time of this publication there was a bug in the initiative code and the DM running the tool cannot use macro nodes for this.
-
-You can also set up your character sheets to be able to be rolled from.  To do it, you will just need a special node that you can find here:
-
-www.geocities.com/woody_j_dick/initiative.xml
-
-You can put it directly into OpenRPG by right clicking on your gametree, pressing &quot;Insert URL&quot; and putting that URL above into the box that appears.  Even the DM can use that node for rolling his initiatives.
-
-CAUTION!  Do not rename the node.  It will not work unless it has that name.
-
-
-The last button, &quot;Keep list&quot; is for Whitewolf players who need to use the list twice.  If you edit the list, and want to keep the edited copy, then just press that and it will save the list so all you need to do is hit refresh to get it back.
-
---------------------------------------------------------------------------------
-
-OpenRPG is a great program, no doubt about it.  And it's best quality is that it is opensourced, meaning anyone can look at the code and alter it to make it work better.  One such person, the one that compiled this tutorial no less, is going to capitalise on this free advertising to say a few quiet words about his webpage.
-
-www.geocities.com/woody_j_dick/OpenRPG.html
-
-The 8.3 Convention webpage, it offers many 'additional extras' That are not yet included in the main program.  Not only are the upgrades good for the current versions of OpenRPG, but it also retains a list of upgrades for previous versions, in case you want to go back and use that 'good ole' 9.4 or 9.6 client with the modern day servers.
-
-</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="About" version="1.0">
-    <form height="240" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="OpenRPG" version="1.0">
-      <text multiline="1" send_button="0">OpenRPG is an online chat program designed to let people all around the globe roleplay together.  It supports the use of maps, character sheets, dice, specialised tools, and much more.  We welcome you to the OpenRPG family.</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="This Tutorial" version="1.0">
-      <text multiline="1" send_button="0">This tutorial was written by Woody to replace the older and aging Idiot's Guide.  This tutorial was written to be used for versions 0.9.8a and beyond. If, at any time, you spot a discrepancy between what this tutorial says and how your OpenRPG program actually works, please go onto the OpenRPG forums from www.OpenRPG.com and post your discovery.
-
-A special thanks goes to Harvester Inc., for assisting Woody.  Of course, thanks to the users that provided feedback for the contents contained within.
-</text>
-    </nodehandler>
-  </nodehandler>
-</nodehandler>
--- a/orpg/templates/nodes/Userguide13.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,564 +0,0 @@
-
-<nodehandler class="tabber_handler" icon="tabber" module="containers" name="User's Manual for OpenRPG 1.3" version="1.0">
-  <nodehandler class="textctrl_handler" icon="note" module="forms" name="Updates" version="1.0">
-    <text multiline="1" send_button="0">From 1.0.3 version
-
-
-I added a section for the user rolls and moderation, also i updated the section on the map for OpenRPG 1.3. And added an explination for the Text View Option in the other features section.
-
-
-Raburn</text>
-  </nodehandler>
-  <nodehandler class="tabber_handler" icon="questionhead" module="containers" name="Idiot's Guide to OpenRPG v. 1.3" status="useful" version="1.0">
-    <nodehandler class="form_handler" icon="form" module="forms" name="About" version="1.0">
-      <form height="240" width="400"/>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="OpenRPG" version="1.0">
-        <text multiline="1" send_button="0">OpenRPG is an online chat program designed to let people all around the globe roleplay together.  It supports the use of maps, character sheets, dice, specialized tools, and much more.  We welcome you to the OpenRPG family.</text>
-      </nodehandler>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="This Tutorial" version="1.0">
-        <text multiline="1" send_button="0">This Tutorial was created by Woody for use with OpenRPG. It was thrown together and updated for use with 1.3 by Raburn. A special thanks goes to HInc for the material that they made for use in this tutorial.</text>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Introduction" version="1.0">
-      <text multiline="1" send_button="0">Welcome, Mateys, to the online gaming universe of the OpenRPG!  By now you have successfully downloaded and installed the program or you would not be able to read this document.  But we are not here to discuss what you already know, we are here to get around to telling you how to do those things you don't know.</text>
-    </nodehandler>
-    <nodehandler class="form_handler" icon="form" module="forms" name="Chatting" version="1.0">
-      <form height="400" width="400"/>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Art Of The Chat" version="1.0">
-        <text multiline="1" send_button="0">The basics:
-
-Alright.  Let us start at the beginning.  Many many years ago the dinosaurs roamed the planet.  But then an asteroid, now most commonly known as &quot;Bill Gates 1,&quot; crashed into the earth and wiped them all out, turning them into oil.  The basic upshot of all that is with this oil we have created electricity which is now running the program.
-
-Before we start it is necessary to make a name for yourself.  Why?  Well, you wouldn't like to be going around with everybody knowing only as 'blankman' would you?  To type in your name, go up to the top left window, and dragging down the &quot;OpenRPG&quot; menu bar press &quot;Settings&quot;.  in there you can alter your name and colours.
-
-You can also rename yourself in a much more simple way by typing in the command &quot;/name &quot; and your name behind it in the chat window.  I just made you go into the settings so that you know where they are later.
-
---------------------------------------------------------------------------------
-
-Now that you have yourself labled, you are probably wondering &quot;where's all the chat?&quot;  Well, my friend, we are here to answer that.  As your program booted up, it should have brought up a four-window layout.  The Gametree Window is in the top-left, the Player Window is the bottom-left, The Chat Window is the bottom-right, and the Map Window is the top-right.  We will first concern outselves with getting that lower right window to do the work and play with the others later.
-
-To get the chat window to work, first we actually need a place to chat.  To do this, we need to browse the list of rooms on what is known as the Tracker.  To open the tracker window go to the menubar on the top and under the menu &quot;Game Server&quot; click on &quot;Browse Tracker&quot;
-
-As you can see, a new window popped up.   This is the Tracker Window.  On the left you will see a list of various servers running OpenRPG online.  Click on the one at the top of the list and press &quot;Connect&quot;.
-
-After pressing the &quot;Connect&quot; button you will join that server and be instantly dropped into it's lobby.  Welcome to your first chatroom.  Feel free to stay in this room as long as you like or move off to another room listed on the Tracker.  When you first turned on OpenRPG the chat window filled up with all the different chat commands available.  If you are like me and have forgotten them by now you can either click on the text display box and press PageUp   or click on the little text entry box and type in &quot;/help&quot;.
-
-Should you wish a way to scroll up instead of 'PageUp'ing you can increase the amount of lines the Chat Window stores by making the Buffer Size larger.  You can do this by changing the &quot;buffersize&quot; setting in the Settings menu or by using /lines [number] replacing [number] with the number of lines..  A good setting is 100-200 lines though you can have it as large as you want (though it is warned against having it larger than 1000 as large numbers tend to increase lag.)
-
-------------------------------------------------------------------------------
-
-By now I'm sure you are also wondering what that status thingy in the bottom left window is.  If you notice, every time you type a message in the chat window your status changes.  And when you finish your msg (or sit for 5 seconds waiting) it changes back to Idle.  What a clever invention.  Of course, if you wish to set your own status to override &quot;Idle&quot; temporarily, just type in the chat window &quot;/status My_Status&quot;; replacing &quot;My_Status&quot; for whatever msg you wish (no more than 18 letters can be seen though).
-
-As for now, spend some time and enjoy yourself in the lobby... we can come back to the tutorial when you are ready to learn about Rolling dice, whispering, and creating and using character sheets.</text>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="form_handler" icon="form" module="forms" name="Dice Rolling" version="1.0">
-      <form height="400" width="400"/>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Rolling Dice" version="1.0">
-        <text multiline="1" send_button="0">Dice:
-
-I'm astonished.  82% of all people who use this program never bother to read the tutorial, let alone come back to it.  Then again 67% of all statistics are made up on the spot so we'll leave that for now and get on with what we are doing
-
-Now, to get back to business.  By now you've hopefully held a conversation with someone (or at least yourself) in our chatroom and now I'm sure you're wondering &quot;How can I roll some dice so I can smite those foolish mortals.&quot;  Well, don't be discouraged, because that is what I'm here for.
-
-To roll dice you have two options.  you can simply press the button on the dice toolbar  or you can type in how many times you wish to roll.  As pressing buttons is mostly self explanitory, this part will only cover typing in dicerolls.
-
-The second way is a little more advanced, and powerful.  You can also roll dice by typing them into your text intry box under the dice toolbar (where you type your normal chat messages).  to do so, first choose how many dice you want to roll.  example:
-
-1
-
-now, put the letter &quot;d&quot; after that.
-
-1d
-
-then put the dice type (number of sides):
-
-1d20
-
-And to finish it off, put the square [ ] brackets around the dice and hit enter
-
-[1d20]
-
-you'll see it rolls a dice into the chat window.  Magic. we can even do things like having multiple types of dice inside it in various mathmatical combinations:
-
-[1d20+4d6-12]
-[3d8+2]
-[1d1-1]
-
-
-------------------------------------------------------------------------
-
- now we let the fun begin.  Inside the square brackets we can also add special modifiers.  it'll come in the following format:
-
-[ 1d20.mod(#) ]
-
-you can even have multiple modifiers if you wish.  the list of all of them are below:
-
-.ascending()
-lists your dicerolls from lowest to highest
-
-.descending()
-lists your dicerolls from highest to lowest
-
-.takeHighest(#)
-takes the highest # amount of rolls
-
-.takeLowest(#)
-takes the lowest # amount of rolls
-
-.extra(#)
-rolls 1 extra dice for every Original roll that gets above the #
-
-.open(#)
-rolls an extra dice for Every roll that gets above the #
-
-.minroll(#)
-no dice will roll below #
-
-.each(#)
-adds # to each diceroll
-</text>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="form_handler" icon="form" module="forms" name="Whispering and Ignoring" version="1.0">
-      <form height="400" width="400"/>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Whispering and Ignoring" version="1.0">
-        <text multiline="1" send_button="0">Of course, not everything should be heard.  This is true twice over in this chapter, as we will be discussing how to whisper and how to ignore.
-
-Whispering is a very simple task in OpenRPG.  First type in &quot;/w &quot; in the text entry box.  next, type in the ID number of the person you wish to whisper to and add an equals sign, so it looks like this:  &quot;/w 4=&quot;.  Add your message to the end of that and hit enter.
-
-/w 4=Hello ID number 4.
-
-You can even have multiple ID numbers in there.   Just seperate them up with a comma between each one, like so:
-
-/w 3, 4, 12=Hey, I dare you to poke that Woody
-
-Of course, if you don't want to type out the weird ID numbers you can always just right click on those little Easter Island Heads next to the person's name in the bottom left player window.  You can then select &quot;whisper&quot; and it will put the whisper command into your text entry box automatically.
-
--------------------------------------------------------------------------------
-
-Sometimes there is someone that will just really get on your nerves.  Be it that they keep sending the same line of text to the chat, or maybe that they are spouting out Britney Spears lyrics nonstop.  Either way, you'll probably want to hear less of them.
-
-Well fear not!  for by just typing in &quot;/i their_ID_#&quot; (changing &quot;their_ID_#&quot; for their ID number) and hitting Enter, then they will be added to your ignore list and no further messages will be heard by them.  Should you wish to take them off again (in case you go the wrong guy) just type the same thing and it'll toggle it off.  You can also get a list of who's on your ignore list just by typing in &quot;/i&quot;
-
-Simple as that.</text>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="tabber_handler" icon="tabber" module="containers" name="The Map" version="1.0">
-      <nodehandler class="form_handler" icon="form" module="forms" name="General Map Info" version="1.0">
-        <form height="400" width="400"/>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Of Maps and Miniatures" version="1.0">
-          <text multiline="1" send_button="0">The Map:
-
-Now comes the hardest part of the tutorial.. describing how to use miniatures (minis)  and background images.  Well, the first step is to bring up the map.  Fortunately the new OpenRPG now loads maps differently than previous versions.  Likewise, it no longer seems to cause crashes for Windows users.  No longer will your client lag, lock up, or crash when loading images, large or small.  The entire map will now load in the background while you continue with your normal activity with the program.  Additionally, images, once loaded, will also be cached (stored) in RAM (up to 64; overflow is handled by randomly purging images within the cache to make room for new images).  That means switching back and forth between maps, in the same session, will result in instantaneous access to your map; no more waiting.  Furthermore, not only are your images loaded in the background, but they are loaded concurrently.  That means your map will be available faster than ever!  Hopefully these new innovations will lead to a renewed usage of the map.  Even modem users have indicated that using maps are now fun again!  Anyway, on with the tutorial.
-
-The Map Window is where most of your image viewing will reside.  In it you can manipulate miniatures and maps to give your players a well good idea of what your gaming world looks like.  In case you haven't guessed, it's the top-right window.  Looking at the Map Window, you'll see all of the basic operations needed to load an image and edit the map.  Let us attempt to load our first picture.  At the bottom of the map window you'll see a large box where you can type in text.  This is where you put  the Web-page Address for the image you wish.  Let's type in this URL/URI:  http://www.openrpg.com/images/mins/amazon.gif.  Notice that there are many great miniatures ready for you to use at OpenRPG's home-page.
-
-After you have typed it in press the &quot;add miniature&quot; button, sit back, and watch as it loads the beautiful amazonian woman (well, almost) into the map window.  Please note, however, all images need to be on web-pages and served up by a web server... you cannot load directly from your hard drive.  Well, you can, but no one else will be able to see it.  The reason being is because OpenRPG's client actually one giant web browser.
-
-Feel free to move it about, get a feel for how it works.  You'll see at the moment that the amazon seems to hop from grid square to grid square.  Well... if you're like me, you don't like being confined to grids or rules.  So let's get rid of that grid, shall we?  Again, looking at the map window, you will see a little red diamond thing.  They say it is a compass but it just looks like a flying fish to me.  Anyway.. click on that and it will bring up all the map settings.  In there you can change the size of the map, what color it is, or even load up a background on which all the mini's sit ((say, a dungeon map you drew or perhaps that picture of Britney Spears I know you have lying around)).  The thing we are interested in the most, though, will be the grid settings at the bottom.  As you can see, you can change the size of the grid and switch the grid from square(4 sided) to hex (6 sided).  You'll also be able to let mini's either abide by the grid, or become free from the black lined prison.  Let us turn off the &quot;snap to grid&quot; and press &quot;apply&quot;.  Also note that you can also make the grids disappear by making them match the background color, however, this is not the ideal way to do it as it still requires processing to draw and redraw the grid lines, even if they blend in without being visible.
-
-Now, go back into the map window and try moving your mini again.  You'll see that it now moves freely, and ignores those lines.  But ignoring them is not enough, did I hear you say?  You want them gone?  Ok.  Let's go back into the settings (the red star button) and this time change the grid size to zero.  Pressing 'apply' you will see that the grid has disappeared entirely from map.  Course, if you want it back, just go put in the size again (50 is default).  Feel free to make the grid size match your miniature and map scale.  Also, if you prefer to have the snap to grid, however, do not feel that it provides enough resolution in miniature movement, feel free to set the grid size to half or one forth of what your actual scale is.  This way, you miniatures will still fit nicely as well as be able to use the &quot;snap to grid&quot;, however, you'll better be able to stagger your miniatures or slightly offset tiled map sets.
-
-
-Tiled Map Sets:
-
-Often, DM's and GM's have the need to present a map to their players, however, they do not which to reveal the whole map and/or map section to their players.  After all, it does remove a lot of surprise if everything is right before the player's eyes.  Enter three new miniature options: &quot;Lock to back&quot;, &quot;Lock to front&quot;, &quot;Unlock Front/Back&quot;.  Previous to these options being available, either the whole map had to be loaded by changing the background image or players and DM's where forced to struggle when map sections were loaded as if they were miniatures.  Even though there was z-ordering options available, it was still tedious as miniatures would often disappear behind a map image.  Now, entire maps can be built before as game and loaded all at once, without giving away any surprises.
-
-By loading all of your map sections together as miniatures and marking each one visible or not visible, you can have great fun again with your maps!  Wait a minute, isn't this the same boat we were on before.  Well, enter the three new options.  Using the &quot;Lock to back&quot; option on each of your map sections, it will force them to always stay on the bottom of the z-order (stacking) of your miniatures.  That means, you'll now be able to change the z-order of your miniatures while all of them stay on top of your map image.  In other words, while the image is locked to the back of the z-order, it acts just like a background image should.  To restore a miniature to normal z-ordering, simply using the &quot;Unlock Front/Back&quot; option and it will once again be ordered just as any other miniature is.
-
-Wait a minute!  That's only two of the three options that you mentioned.  Well, the third option allows for even more flexibility in what DM's and GM's can present to their players, even on a visible map section.  Enter, the poor-man's fog-of-war.  By creating a &quot;mask&quot; in just about any shape you like (feel free to use transparent colors on gifs as needed), you can effectively lock the &quot;masking&quot; image to the top of the z-order which will hide a section of your visible map.  While this is still somewhat tedious, it will allow for much finer grain of control of what is and is not visible on your maps!
-
-
-Looking here, moving there:
-
-Directional markers have been a part of OpenRPG for some time now, however, there use is going to be better explained here.  If you notice, each miniature has a &quot;facing&quot; and &quot;heading&quot; available to it.  These serves not only to indicate a miniature's facing, but it's current direction of travel.  After all, you're quite able to turn your head and talk to your buddy while walking in a direction different than the one your head is pointed.  While this feature mostly serves board game players, RPGer's may find use in this too, especially when making canned maps.  Imagine, the 'ol evil cleric behind the podium with his back to you.  Now, you can make it clear on the map.  Oh wait, the cleric's minions do not have their back to you, rather, they are standing to his side and looking directly at him.  Closer look, and you see that the cleric too had his head turned to his minions in conversation.  Again, this can be expressed on your map.  Information like this makes it easier for the players to understand that the back-stab that they obviously want to do, won't be so easy to pull off.  All this, without having to verbally describe every little detail.  After all, isn't this what the maps is for?  Enjoy!
-
-
-Saving and Loading Your Map:
-
-Don't forget that you can save your hard work.  Once you have built your map, be sure to right click on the map and hit &quot;Save Map&quot;.  When you need it again, just do &quot;Load Map&quot;.  You don't even need to delete the contents of the previous map.  The client does all that for you!  Don't forget, if you load a previously viewed image, the caching will considerable speed the rate at which it's visible to you and your players.  Using a common set of miniatures helps to take advantage of this fact.
-
-The Other Modes:
-
-Now, you can also use something called map modes. This feature lets you draw, and use rulers and other fun stuff. To turn it on you right click in the map, go under switch modes and choose either whiteboard (drawing) or ruler (ruler with distance gauge). This can be useful if you ever needed to point out something to someone. To remove a line just right click on it and click remove, its as easy as that!
-</text>
-        </nodehandler>
-      </nodehandler>
-      <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Map Tabs and Toolbar" version="1.0">
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Map Toolbar" version="1.0">
-          <text multiline="1" send_button="0">This is the toolbar in the lower right hand side of the map, there you can, from left to right:
-
-Zoom in the map
-
-Zoom out
-
-View Map Properities
-
-Load Map
-
-Save Map</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Backround Layer" version="1.0">
-          <text multiline="1" send_button="0">This layer is used to change the backround of the map. there are 4 options
-
-none - no backround at all
-
-Texture - repeats the picture linked to the link in the box to the right of it all over the map to fill up the whole map
-
-Image - Displays the image at its full size once in the upper left corner of the map
-
-Color - Chooses a color for the backround
-
-
-Footnote:
-
-Only weblinks can be used for the backround at the moment, that and maps you make before hand and save from within OpenRPG.
-
-And if you right click on the map, you can load map, save map, go into a properities window where you can change other things such as the Grid (same as when u use the grid tab) and all the backround stuff.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Grid Layer" version="1.0">
-          <text multiline="1" send_button="0">In the grid layer (and in the map properities window which can be opened by right-clicking on the map) you can change the Pixels per Square (size of each square or hex); if there are lines and if they are dotted or solid; whether there are hex or square units; if the minitures are placed on the grid and can only be moved to another square or hex; the color of the grid; and a button to apply all changes.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Miniature Layer" version="1.0">
-          <text multiline="1" send_button="0">The miniature layer is where you take miniatures from the web, and put them on the map, this is done by putting the link in the box right above the Miniatures tab to the image of the minitiature, and clicking &quot;--&gt; Add Miniature&quot; Also there are a few more things you can do:
-
-Auto Label - Automatically label the mini based on the image name (ex. image.gif is                         named image1)
-
-                                    Right Click on Mini Menu Options
-
-Miniature Z-Order - Send the image to the front (be ontop of the other minis) or, back, or up a layer, or down a layer (like in MSWord), or lock it in a poisition
-
-Set Facing - Make a red arrow point to where the mini is &quot;facing&quot;
-
-Set Heading - Make a blue arrow point to where the mini is &quot;heading&quot;
-
-To Gametree - Copy the mini to the gametree
-
-Remove - Removes the mini from the map
-
-Snap to alignment - changes how the mini snaps to the grid
-
-Properities - lets you change most of whats above and lets u hide the mini by making it invisible</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Whiteboard Layer" version="1.0">
-          <text multiline="1" send_button="0">The whiteboard layer is used to draw on the map using a pen, you can change the pen color, and if you right click on a line you can delete it, or if you right click anywhere on the map you can delete all lines.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Fog Layer" version="1.0">
-          <text multiline="1" send_button="0">The fog layer is a new thing in OpenRPG to help hide things from the players, but not the GM, this is used by selecting the &quot;Fog&quot; tab, turning it on, then right clicking on the map (as a GM) and clicking Fog Mask, choose a color, then right click again and select hide all. This will activate the fog layer all over the map, and while the fog layer tab is clicked, u can shade and unshade portions at will.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="The General Layer" version="1.0">
-          <text multiline="1" send_button="0">The general layer is used for changing the map size and loading the default map (the green map you see on a lot of servers)</text>
-        </nodehandler>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="form_handler" icon="form" module="forms" name="Nodes and Character Sheets" version="1.0">
-      <form height="400" width="400"/>
-      <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Nodes" version="1.0">
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="&lt;b&gt;The Basics&lt;/b&gt;" version="1.0">
-          <text multiline="1" send_button="0">&lt;a name=&quot;c3&quot;&gt;&lt;/a&gt;
-alright.. by now you have grasped the basics on how to chat, so we will move on to the next phase: character sheets.  This part of the tutorial will cover how to make a full usable document from the nodes.
-
-Let us first start by describing what the different nodes are and where we can find them</text>
-        </nodehandler>
-        <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Nodes" version="1.0">
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name="Nodes and Sheets" version="1.0">
-            <text multiline="1" send_button="0">------------------------------------------------------------------------
---Character Sheets And Nodes
-------------------------------------------------------------------------
-
-Character sheets are the wonderful inventions that allow us to hold all the information we want about our characters and gaming worlds.  In OpenRPG they are made up of what we call &quot;Nodes.&quot;  These nodes are the building blocks for creating all manner of character sheets and can be rearranged into whatever form you wish.
-
-but to understand the nodes, we must first know how they work.  This chapter is dedicated to explaining the function of each node.  To get a new node, just find the one you want in the &quot;Templates&quot; tree and doubleclick on it.  That will put a fresh blank one in the gametree at the top.</text>
-          </nodehandler>
-          <nodehandler class="form_handler" icon="form" module="forms" name="Nodes" version="1.0">
-            <form height="700" width="400"/>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Text Node" version="1.0">
-              <text multiline="1" send_button="1">The Text Node is the very basic and most fundamental part of the character sheet.  It is where we store most of our important information.  To use a text node, first you must right click on it and press &quot;design.&quot;  This will bring up the text node's option's window.  In there you can choose whether the Text node only has one line or if it is a small text window, what it's title is, and whether it has a send button or not.  The Send button will send whatever is in the text node directly to the chat.</text>
-            </nodehandler>
-            <nodehandler class="listbox_handler" icon="gear" module="forms" name="List Box" version="1.0">
-              <list send_button="0" type="0">
-                <option selected="1" value="0">The List Box is a marvelous tool that allows you to have ...</option>
-                <option selected="0" value="0">dropdown menus and a variety of checklists and radio boxes.</option>
-                <option selected="0" value="0">To use a List box, right click on one that you created in your</option>
-                <option selected="0" value="0">gametree and press &quot;design&quot;.  this will bring up a window </option>
-                <option selected="0" value="0">where you can choose what type of list box it is and what </option>
-                <option selected="0" value="0">options are inside of it.  Simple as that!</option>
-              </list>
-            </nodehandler>
-            <nodehandler class="rpg_grid_handler" icon="grid" module="rpg_grid" name="Grid" version="1.0">
-              <grid autosize="1" border="1">
-                <row version="1.0">
-                  <cell size="144">The Grid lets you keep tables</cell>
-                  <cell size="138"></cell>
-                </row>
-                <row version="1.0">
-                  <cell></cell>
-                  <cell>like stats, or saving throws.</cell>
-                </row>
-                <row version="1.0">
-                  <cell>You can arrange numbers</cell>
-                  <cell></cell>
-                </row>
-                <row version="1.0">
-                  <cell></cell>
-                  <cell>more easily in a grid than</cell>
-                </row>
-                <row version="1.0">
-                  <cell>you can with a text node.</cell>
-                  <cell></cell>
-                </row>
-              </grid>
-              <macros>
-                <macro name=""/>
-              </macros>
-            </nodehandler>
-            <nodehandler class="webimg_handler" icon="image" module="forms" name="Image" version="1.0">
-              <link href="http://my.openrpg.com/images/logo200x60.jpg"/>
-            </nodehandler>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name="Images allow for images. Just right click to provide the webpage addy they're at" version="1.0">
-              <text multiline="0" send_button="0"></text>
-            </nodehandler>
-            <nodehandler class="link_handler" icon="html" module="forms" name="OpenRPG.com link" version="1.0">
-              <link href="http://www.OpenRPG.com"/>
-            </nodehandler>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-              <text multiline="0" send_button="0">you can change the link node's url by right clicking on it in the gametree</text>
-            </nodehandler>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-              <text multiline="1" send_button="0">Now that we know what the individual nodes do, we need ways to group them together.  continue to the next page to learn about the different forms of groups.</text>
-            </nodehandler>
-          </nodehandler>
-          <nodehandler class="form_handler" icon="form" module="forms" name="containers" version="1.0">
-            <form height="700" width="700"/>
-            <nodehandler class="form_handler" icon="form" module="forms" name="Form" version="1.0">
-              <form height="400" width="400"/>
-              <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-                <text multiline="1" send_button="0">The Form is the basic and most used container of the lot.  It is what is able to hold all the other types of containers AND nodes.  Forms can also be placed within other containers as well, allowing for you to 'group up' a bunch of nodes in a form, then put that form as one page on a tabber. You can adjust the size by right clicking on a form in the game tree, pressing design, and adjusting the height and width</text>
-              </nodehandler>
-            </nodehandler>
-            <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-              <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-                <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-                  <text multiline="0" send_button="0">text</text>
-                </nodehandler>
-                <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-                  <text multiline="1" send_button="0">text</text>
-                </nodehandler>
-              </nodehandler>
-              <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-                <text multiline="1" send_button="0">The splitter allows you to break a character sheet into segments, and have different datas side by side.  you can't have more than two single things inside a splitter, however you can put forms (or even other splitters!) inside a splitter.</text>
-              </nodehandler>
-            </nodehandler>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name="Folders" version="1.0">
-              <text multiline="1" send_button="0">Another node that is useful for keeping everything together is the folder. You can only view the stuff in it by using pretty print, but if you want to save a lot of work in one area, it is the thing you want to use.</text>
-            </nodehandler>
-          </nodehandler>
-        </nodehandler>
-      </nodehandler>
-      <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Character Sheets" version="1.0">
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Moving Characters from almost ANY Character Generator to here." version="1.0">
-          <text multiline="1" send_button="0">The following are stpes on how to move your character sheets from your favorite Character Generation program into OpenRPG.  It's very quick and clean cut.
-
-1) first, using your character generator, you convert your character to either txt format, or, preferably (if you have the ability) HTML format.
-
-2) Then, you go to wizards.put a text block into the gametree
-
-3) if you are using txt, select all, and copy.  if you are using HTML format, edit it using notepad, but don't change any of the HTML Program. then select all and copy
-
-4) now, going back into OpenRPG, right click on the text block you created and push 'edit'
-
-5) clear the text block of the few words of text that appear there then paste the copied info into by either rightclicking-paste or pressing 'ctrl v'
-
-6) then name your character in the Title then close the text block.  Finished
-
-no more need to create character sheets!  That simple and any time you want to see it, just doubleclick on the text node.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Create Your Own Character" version="1.0">
-          <text multiline="1" send_button="0">((before we begin, see the character sheet repository:
-   http://openrpg.wrathof.com
-for pre-made character sheets.))
-
-
-Character Sheet creation (By Melanthos):
-
-So you wanna make a character sheet, huh? Well, follow these few short steps and you'll be on your way to Sheet Creation Godhood...or not. But don't blame me if you don't read this and can't make yourself a sheet. I'm going to guess you have a basic understanding of how the nodes work. I'll be using Harvester Incorporated(TM)'s Faction Wars(TM) as an example.
-
-First, you'll need a tabber. You can find it under containers in the templates node.  Click the + to the left of templates then click the plus next to containers.  Next double click the Create New Tabber.  Got it? Good. Now, you'll need a form. Forms are what we use to create each page of the tabber. They hold the rest of the nodes neatly, and open up - unlike groups, which cannot be opened in a sheet. To create a form double click on Create New Form.  You will notice two new nodes at the top of the game tree.
-
-
-        Tabbers, Forms, and Text-boxes, OH MY!
-
-Alright. Here is where I store the basics of the character. Since I don't like to scroll too much, I've broken down the information even more, so that I can fit into smaller tabbers and forms. First I'll create a second tabber. This will hold all the basic info - Level, Class, Player &amp; Character name, and a few other things. Since I've got 8 things I want to list, I've broken them up into 2 seperate groups, which have been put into different forms: General Info, and Specific Info. For simple things like name and level, I suggest using single-line text boxes. I've gone ahead and made 8 of these, naming each of them one of my 8 items and stuck them into their forms. Now that I've finished that, I'll put the two forms under my second tabber, and put that into my big form, &quot;General.&quot; I've done the same thing with the Attributes. Most of the sheet uses this principal, so I won't go into each form. Kinda redundant.
-
-
-                   List Boxes &amp; Die Creation
-
-Alright, for my second form, Vitals, I need some die-rollers. Since I don't need to change the rolls often, I've decided to use List Boxes to hold all my rolls. It's not too hard, and it's a really easy way to store rolls(It can be used for other things, but this is the best use I've found.): Now you don't have to type out those dice every time you wanna attack. First, I've created myself a List Box. Next, I'll decide how I want my list box to be shown: There are four choices. Drop Down, List Box, Radio Box, and Check List. Since I only need to roll one at a time, I've chosen Drop Down. But to show you how the Drop Down and Check List options work, I'll change things a bit and make a List Box and a Check List as well. When editing, make sure to click the &quot;Send Button&quot; box.
-
-
-        Drop Down
-
-The Drop Down is the least space- consuming of the List Box options. It's just like a single-line Text Box, except it holds more than one line. Click the arrow on the right to make it drop down, and click the die you want to roll. Then hit the Send button, and POOF! Your die has been rolled to the chat window.
-
-
-        Check List
-
-The Check List is a neat option. It lets you roll more than one die at a time. All you have to do is check the box next to the die (or dice) you want to roll, and POOF! Your dice have been rolled. Neat, eh?
-
-           Splitter
-
-Now what could these be used for, you wonder? Not much, but there are a few things. I've used it to hold my different abilities. It's easier for me to just see my choices than to flip between tabbers or scroll down and back up every few seconds.
-
-
-The rest is pretty easy. Just keep on with the things you've done so far, and in no time you'll be on your way to creating great sheets! Most of sheet creation is your personal preference. If you ask Woody, he might say something completely different than I might. Of course, you should make the sheets the way you want them. This is just to get you started. After you've got the basics of sheet making down, you can play around with sheets and nodes and things until you've got the sheet perfect for you. GOOD LUCK!!
-
-
---Melanthos, Founder &amp; Game Designer - Harvester Incorporated</text>
-        </nodehandler>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="form_handler" icon="form" module="forms" name="Server Control" version="1.0">
-      <form height="400" width="400"/>
-      <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Server Control" version="1.0">
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Running Your Own Server" version="1.0">
-          <text multiline="1" send_button="0">Creating a server:
-
-OpenRPG has come a long way since the dark ages of gaming.  With this new version we can now create servers on-the-fly!  No more black boxes or strange voodoo magic.  Just click on your &quot;Game Server&quot; menu, and select &quot;Start new server.&quot;  Fill in the options and away you go!  the server will appear instantly on the list.
-
-Of course, this won't provide you with all the same powers that the full server does (but it will for most if them).  While you can create a server on the short term, if you want to have a longterm dedicated server running which you can control, you'll want to run the OpenRPG Server in your start menu-programs-openrpg (or mplay_server.py in your openrpg folder).
-</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Running a Dedicated Server" version="1.0">
-          <text multiline="1" send_button="0">Well, maybe not any money in creating a server on this program, but there are definately perks to running one.  But to run one we must first understand what they do.
-
-A server is the mother for all of us on OpenRPG.  It runs all of our major commmands, keeps us all talking together, and hosts all the games on OpenRPG.  When you first connected to OpenRPG you had to choose a server from a list in the tracker, on the left.  Now let us put your name (or at least your computer's) out there so others can flock to you.
-
-For this we must return to your OS.  Go into your computer, into the OpenRPG folder.  In there, you will see a file marked:
-
-mplay_server.py
-
-You can also find it in your start menu, right next to the OpenRPG program itself.  Once you find it, (double)click on it.  The first thing that will come up is a python MSDOS window... It will first prompt on if you wish for your server to bee seen by the OpenRPG tracker list.  Press &quot;Y&quot; and hit enter (won't get anyone if we don't know it exists).  Next, it will prompt you for a name for your Server.  Write in &quot;Temporary Server&quot; and press enter.
-
-Now the window will start running the various server-y looking bits of code.  as soon as it is up and going, you will told the various commands that are available to the server.  The first one will be &quot;kill&quot;.  this is what you type into the MSDOS window to shut the server down.  &lt;b&gt;**IMPORTANT**&lt;/b&gt; if you shut down the server all rooms on it will close.  You don't want to shut it down if others are using it.
-
-The second command is the &quot;dump&quot; command.  This will list all the people on your server, as well as their ID number.  It really isn't important at this time but it will come in handy later.
-
-Broadcast is self explanitory.  The 'Announce' and 'Remove' features allow you to choose later on if your server can be seen on the tracker, or not.  Dump Groups gets the same info as Dump but does Groups instead of people.  And finally you can bring up this little list of commands at any time by typing 'help' or '?'.
-
-You can type these commands in any time in the python server window.  Go ahead and try 'help' or 'dump' and see what comes up.
-
-Alright!  That's it.  to access your server, run you OpenRPG program as normal (with the server MSDOS window in the background) and log onto your server as we had shown you in chapter 1.  This will come in handy if there are no Servers running and you wish to use OpenRPG with, perhaps your gaming buddies or maybe some underworld kingpins you need to 'have a talk' with.
-
-And From All of us at OpenRPG HQ, we wish you good gaming!</text>
-        </nodehandler>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Rolls and Room Moderation" version="1.0">
-      <nodehandler class="form_handler" icon="form" module="forms" name="Rolls" version="1.0">
-        <form height="400" width="400"/>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="General Info" version="1.0">
-          <text multiline="1" send_button="0">OpenRPG now uses a roll system where when you join a room other than the lobby you are assigned a roll, you change rolls by either using the /roll command (this also lists all the rolls in the room if that is all you type in) or right clicking the name of the player in the player list window. do change a roll you need to know the room administration password.</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Lurker (Whitish Grey)" version="1.0">
-          <text multiline="1" send_button="0">A lurker cannot talk when room moderation is turned on, also he cant change any of the map options. He is basically the watcher in a game, and is the roll that the person gets when he first joins the room</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Player (Black)" version="1.0">
-          <text multiline="1" send_button="0">Player is the main roll for a player in a game, he can do some map functions, and can talk automatically if room moderation is turned on. He is...well...the player</text>
-        </nodehandler>
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="GM (Red)" version="1.0">
-          <text multiline="1" send_button="0">GM (Game Master) is the person who makes the room by default, he also can do all the stuff in the room, including use the map, the only thing he cannot do is change roles and turn on and off room moderation, unless he knows the administration password for the room.</text>
-        </nodehandler>
-      </nodehandler>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Room Moderation" version="1.0">
-        <text multiline="1" send_button="0">Room Moderation is used to make it so only certain people can chat in a room, this is usually used to prevents spammers who enters the room, but can be used for anything you want. It is turned on and off by right clicking on a name and turning it on (you need the administration password). After that you can right click on the name of a person you want to let talk, or not let him talk by giving or taking voice under the Moderation sub menu.</text>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Setting Up Rooms, Games, and Ignoring" version="1.0">
-      <text multiline="1" send_button="0">So now that you have your server, your custom character sheet, and have talked enough players into starting a game, you'll want to set up a private room so that you aren't disturbed by every wandering weirdo or Woody that happens upon your server (and be forwarned, you will find that various people will wander from server to server.  Do not be frightened, most of them are harmless).
-
-So, lets pull up your tracker window.  If you haven't done so already, be sure to connect to your server.  Once in there look onto the right side of the tracker window.  You will see some boxes marked &quot;Room name&quot;, &quot;Boot password&quot;, and if you check a little box, &quot;password&quot;.  the first two are rather self explanatory, and the last one is to lock your room in case you don't want to be bothered.  Be sure to tell your players what it is though.
-
-If you don't password protect a room you may get people wandering in looking for a game or just lurking watching your game.  If you don't want them in there you should first let them know and ask them to leave.  If they refuse your request then boot them.  It is very rude to boot someone from a non passworded room with out warning.
-
-Now that you have your custom built char sheet and you have talked enough players into starting a game, it's time to set up your own room.  Let's bring up that Tracker window again ((under the Game Server menu)).  Looking to the bottom left of it, you'll see a little box that allows you to type in your own room name and add a password if you like.  Let's start a room called &quot;Working on that darned fun tutorial&quot; and not put a password up.
-
-as you see the room you create will be exactly the same as the lobby, so there is nothing to worry about.  Lets load up our character sheet by right clicking on the &quot;Game Tree&quot; and pressing Insert file&quot;
-
-Now that we have our little char sheet we might as well show the world.  This can be done in one of three ways.  The first way is to right click on it and send it to other players (provided there are any).  This is how other players can get your sheet as they can't see it until you send it to them.
-
-The second way is to send it directly to the chat and let everyone see it there.  go ahead and do that by right clicking on the char sheet and pressing &quot;Send to Chat&quot;.  Now everyone gets to see it as it appears on their text chat window.
-
-the third option, Whisper to Player, is much the same as &quot;Send to chat&quot; only it sends it to a specific person or persons to see in their chat instead.
-
-Of course, there sometimes comes a day when there is a little spammonkey running about.  You know the type.  Just keeps askin pointless questions, hitting you with the same text, and generally making himself a nuesance.  Well fear not!  We have added in a brand new feature that allows you to ignore those unscrupulous people.  In the chat entry box just enter the command &quot;/i player_ID#&quot; and that will put a person on ignore (or toggle them back to un-ignore [you can also right click on the name and press toggle ignore]).  To get a list of ID's who are on your ignore list, just type &quot;/i&quot; alone, with nothing else.  You can even ignore/un-ignore multiple people at once, just put commas (( , )) between the names.  And that's it.  Ignore at your leasure.</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Other Features; Logs, Initiative, Upgrades" version="1.0">
-      <text multiline="1" send_button="0">Other features:
-
-It may seem a little odd that this seventh window is tucked behind some arrows, but I always thought this chapter was a little on the sinful side so over here it now lay.
-
-
-By getting here, you must have had quite a bit of time to read through the rest of the chapters.  Well, let's finish off with what few interesting toys we have left.
-
-To start with, lets talk about logging  To create a logfile, you can just press the disk button in the bottom right corner of the OpenRPG program, and choosing a name and place to save the file.  Badaboom!  a chatlog of everything you have seen is saved.
-
-Of course, most of you will want a way to have it automatically save a log each time it see's text.  To do that, type in &quot;/log to my_log&quot; (replacing &quot;my_log&quot; for what you want to call the file). It should automatically start logging to that filename (and will include the date in the filename you gave it).  if you want to turn it on or off later on, just type &quot;/log on&quot; or &quot;/log off&quot;
-
-Note: The chat logging system no longer appends a datestamp to the logfile
-specified.  This means that for the system to generate the logfile
-
-/foo/bar/gamelog-02-10-01.html for linux or \foo\bar\gamelog-02-10-01.html for windows
-
-Previously the user only had to have &quot;/foo/bar/gamelog&quot; entered as GameLogChatPrefix.
-To get the same logging pattern now, they'll have to set GameLogChatPrefix to
-the following:
-
-/foo/bar/gamelog-%d-%m-%y.html
-
-
---------------------------------------------------------------------------------
-The Text View Tool
-
-This is used if you want to find specific text in the chat buffer or view the raw HTML, its handy also if you want to cut and paste phrases out of the chat buffer.
-
-
---------------------------------------------------------------------------------
-
-The Initiative Tool.  A marvelous invention allowing DMs to organise and handle an otherwise chaotic scene that we know as combat.  Compatable with all versions of OpenRPG, it works incredibly simply.
-
-All that is needed is for the DM to press &quot;New Initiative&quot; in the tool, have all of the players and the DM to type in &quot;init [diceroll]&quot; (replacing 'diceroll' for your dice) and hit enter.  An example:
-
-init [1d10+6]
-
-once everyone has done that, the DM pulls up his tool again, hits refresh, and then sorts the list however he wants.  once it is sorted, he just hits &quot;send to chat&quot; and the person at the top of the list is then sent to the chat.
-
-Once all the people have been cycled through, it will say &quot;End of Init&quot; in the chat.  The DM just presses the &quot;Start new Initiative&quot; button one more time and away you go on another round of hacking!
-
-Now, if you are the player and not using the tool, you can even put your init command into a macro node (not a text node) and do it that way.  At the time of this publication there was a bug in the initiative code and the DM running the tool cannot use macro nodes for this.
-
-You can also set up your character sheets to be able to be rolled from.  To do it, you will just need a special node that you can find here:
-
-www.geocities.com/woody_j_dick/initiative.xml
-
-You can put it directly into OpenRPG by right clicking on your gametree, pressing &quot;Insert URL&quot; and putting that URL above into the box that appears.  Even the DM can use that node for rolling his initiatives.
-
-CAUTION!  Do not rename the node.  It will not work unless it has that name.
-
-
-The last button, &quot;Keep list&quot; is for Whitewolf players who need to use the list twice.  If you edit the list, and want to keep the edited copy, then just press that and it will save the list so all you need to do is hit refresh to get it back.
-
---------------------------------------------------------------------------------
-
-OpenRPG is a great program, no doubt about it.  And it's best quality is that it is opensourced, meaning anyone can look at the code and alter it to make it work better.  One such person, the one that compiled this tutorial no less, is going to capitalise on this free advertising to say a few quiet words about his webpage.
-
-www.geocities.com/woody_j_dick/OpenRPG.html
-
-The 8.3 Convention webpage, it offers many 'additional extras' That are not yet included in the main program.  Not only are the upgrades good for the current versions of OpenRPG, but it also retains a list of upgrades for previous versions, in case you want to go back and use that 'good ole' 9.4 or 9.6 client with the modern day servers.
-
-The webpage doesnt have any modifications for OpenRPG at the moment, but it might in a future.
-
-</text>
-    </nodehandler>
-  </nodehandler>
-</nodehandler>
--- a/orpg/templates/nodes/die_macro.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-
-<nodehandler class="dieroll_handler" icon="d20" module="core" name="Die Macro">example roll [1d20+4]</nodehandler>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/templates/nodes/file_loader.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -0,0 +1,3 @@
+<nodehandler class="file_loader" icon="d20" map="" module="core" name="File Loader" version="1.0">
+  <file name="file_loader.xml" />
+</nodehandler>
--- a/orpg/templates/nodes/split.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/split.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -1,3 +1,2 @@
-  <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-    <splitter_atts horizontal="0"/>
-  </nodehandler>
\ No newline at end of file
+  <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0" horizontal="0">
+  </nodehandler>
--- a/orpg/templates/nodes/textctrl.xml	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/templates/nodes/textctrl.xml	Sat Apr 24 08:37:20 2010 -0500
@@ -1,4 +1,4 @@
 
 <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-  <text multiline="0" send_button="0">text</text>
+  <text multiline="1" send_button="0">text</text>
 </nodehandler>
--- a/orpg/templates/nodes/u_idiots_guide_to_openrpg.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,457 +0,0 @@
-
-<nodehandler class="tabber_handler" icon="tabber" module="containers" name="The Ultimate Idiot's Guide to OpenRPG" version="1.0">
-  <nodehandler class="form_handler" icon="form" module="forms" name="About" version="1.0">
-    <form height="240" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="OpenRPG" version="1.0">
-      <text multiline="1" send_button="0">OpenRPG is an online chat program designed to let people all around the globe roleplay together.  It supports the use of maps, character sheets, dice, specialized tools, and much more.  We welcome you to the OpenRPG family.</text>
-    </nodehandler>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="This Tutorial" version="1.0">
-      <text multiline="1" send_button="0">This Tutorial was created by Woody for use with OpenRPG. It was thrown together and updated for use with 1.0 and beyond by Raburn. A special thanks goes to HInc for the material that they made for use in this tutorial.</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="textctrl_handler" icon="note" module="forms" name="Introduction" version="1.0">
-    <text multiline="1" send_button="0">Welcome, Mateys, to the online gaming universe of the OpenRPG!  By now you have successfully downloaded and installed the program or you would not be able to read this document.  But we are not here to discuss what you already know, we are here to get around to telling you how to do those things you don't know.</text>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="Chatting" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Art Of The Chat" version="1.0">
-      <text multiline="1" send_button="0">The basics:
-
-Alright.  Let us start at the beginning.  Many many years ago the dinosaurs roamed the planet.  But then an asteroid, now most commonly known as &quot;Bill Gates 1,&quot; crashed into the earth and wiped them all out, turning them into oil.  The basic upshot of all that is with this oil we have created electricity which is now running the program.
-
-Before we start it is necessary to make a name for yourself.  Why?  Well, you wouldn't like to be going around with everybody knowing only as 'blankman' would you?  To type in your name, go up to the top left window, and dragging down the &quot;OpenRPG&quot; menu bar press &quot;Settings&quot;.  in there you can alter your name and colours.
-
-You can also rename yourself in a much more simple way by typing in the command &quot;/name &quot; and your name behind it in the chat window.  I just made you go into the settings so that you know where they are later.
-
---------------------------------------------------------------------------------
-
-Now that you have yourself labled, you are probably wondering &quot;where's all the chat?&quot;  Well, my friend, we are here to answer that.  As your program booted up, it should have brought up a four-window layout.  The Gametree Window is in the top-left, the Player Window is the bottom-left, The Chat Window is the bottom-right, and the Map Window is the top-right.  We will first concern outselves with getting that lower right window to do the work and play with the others later.
-
-To get the chat window to work, first we actually need a place to chat.  To do this, we need to browse the list of rooms on what is known as the Tracker.  To open the tracker window go to the menubar on the top and under the menu &quot;Game Server&quot; click on &quot;Browse Tracker&quot;
-
-As you can see, a new window popped up.   This is the Tracker Window.  On the left you will see a list of various servers running OpenRPG online.  Click on the one at the top of the list and press &quot;Connect&quot;.
-
-After pressing the &quot;Connect&quot; button you will join that server and be instantly dropped into it's lobby.  Welcome to your first chatroom.  Feel free to stay in this room as long as you like or move off to another room listed on the Tracker.  When you first turned on OpenRPG the chat window filled up with all the different chat commands available.  If you are like me and have forgotten them by now you can either click on the text display box and press PageUp   or click on the little text entry box and type in &quot;/help&quot;.
-
-Should you wish a way to scroll up instead of 'PageUp'ing you can increase the amount of lines the Chat Window stores by making the Buffer Size larger.  You can do this by changing the &quot;buffersize&quot; setting in the Settings menu or by using /lines [number] replacing [number] with the number of lines..  A good setting is 100-200 lines though you can have it as large as you want (though it is warned against having it larger than 1000 as large numbers tend to increase lag.)
-
-------------------------------------------------------------------------------
-
-By now I'm sure you are also wondering what that status thingy in the bottom left window is.  If you notice, every time you type a message in the chat window your status changes.  And when you finish your msg (or sit for 5 seconds waiting) it changes back to Idle.  What a clever invention.  Of course, if you wish to set your own status to override &quot;Idle&quot; temporarily, just type in the chat window &quot;/status My_Status&quot;; replacing &quot;My_Status&quot; for whatever msg you wish (no more than 18 letters can be seen though).
-
-As for now, spend some time and enjoy yourself in the lobby... we can come back to the tutorial when you are ready to learn about Rolling dice, whispering, and creating and using character sheets.</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="Dice Rolling" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Rolling Dice" version="1.0">
-      <text multiline="1" send_button="0">Dice:
-
-I'm astonished.  82% of all people who use this program never bother to read the tutorial, let alone come back to it.  Then again 67% of all statistics are made up on the spot so we'll leave that for now and get on with what we are doing
-
-Now, to get back to business.  By now you've hopefully held a conversation with someone (or at least yourself) in our chatroom and now I'm sure you're wondering &quot;How can I roll some dice so I can smite those foolish mortals.&quot;  Well, don't be discouraged, because that is what I'm here for.
-
-To roll dice you have two options.  you can simply press the button on the dice toolbar  or you can type in how many times you wish to roll.  As pressing buttons is mostly self explanitory, this part will only cover typing in dicerolls.
-
-The second way is a little more advanced, and powerful.  You can also roll dice by typing them into your text intry box under the dice toolbar (where you type your normal chat messages).  to do so, first choose how many dice you want to roll.  example:
-
-1
-
-now, put the letter &quot;d&quot; after that.
-
-1d
-
-then put the dice type (number of sides):
-
-1d20
-
-And to finish it off, put the square [ ] brackets around the dice and hit enter
-
-[1d20]
-
-you'll see it rolls a dice into the chat window.  Magic. we can even do things like having multiple types of dice inside it in various mathmatical combinations:
-
-[1d20+4d6-12]
-[3d8+2]
-[1d1-1]
-
-
-------------------------------------------------------------------------
-
- now we let the fun begin.  Inside the square brackets we can also add special modifiers.  it'll come in the following format:
-
-[ 1d20.mod(#) ]
-
-you can even have multiple modifiers if you wish.  the list of all of them are below:
-
-.ascending()
-lists your dicerolls from lowest to highest
-
-.descending()
-lists your dicerolls from highest to lowest
-
-.takeHighest(#)
-takes the highest # amount of rolls
-
-.takeLowest(#)
-takes the lowest # amount of rolls
-
-.extra(#)
-rolls 1 extra dice for every Original roll that gets above the #
-
-.open(#)
-rolls an extra dice for Every roll that gets above the #
-
-.minroll(#)
-no dice will roll below #
-
-.each(#)
-adds # to each diceroll
-</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="Whispering and Ignoring" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Whispering and Ignoring" version="1.0">
-      <text multiline="1" send_button="0">Of course, not everything should be heard.  This is true twice over in this chapter, as we will be discussing how to whisper and how to ignore.
-
-Whispering is a very simple task in OpenRPG.  First type in &quot;/w &quot; in the text entry box.  next, type in the ID number of the person you wish to whisper to and add an equals sign, so it looks like this:  &quot;/w 4=&quot;.  Add your message to the end of that and hit enter.
-
-/w 4=Hello ID number 4.
-
-You can even have multiple ID numbers in there.   Just seperate them up with a comma between each one, like so:
-
-/w 3, 4, 12=Hey, I dare you to poke that Woody
-
-Of course, if you don't want to type out the weird ID numbers you can always just right click on those little Easter Island Heads next to the person's name in the bottom left player window.  You can then select &quot;whisper&quot; and it will put the whisper command into your text entry box automatically.
-
--------------------------------------------------------------------------------
-
-Sometimes there is someone that will just really get on your nerves.  Be it that they keep sending the same line of text to the chat, or maybe that they are spouting out Britney Spears lyrics nonstop.  Either way, you'll probably want to hear less of them.
-
-Well fear not!  for by just typing in &quot;/i their_ID_#&quot; (changing &quot;their_ID_#&quot; for their ID number) and hitting Enter, then they will be added to your ignore list and no further messages will be heard by them.  Should you wish to take them off again (in case you go the wrong guy) just type the same thing and it'll toggle it off.  You can also get a list of who's on your ignore list just by typing in &quot;/i&quot;
-
-Simple as that.</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="Nodes and Character Sheets" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Nodes" version="1.0">
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="&lt;b&gt;The Basics&lt;/b&gt;" version="1.0">
-        <text multiline="1" send_button="0">&lt;a name=&quot;c3&quot;&gt;&lt;/a&gt;
-alright.. by now you have grasped the basics on how to chat, so we will move on to the next phase: character sheets.  This part of the tutorial will cover how to make a full usable document from the nodes.
-
-Let us first start by describing what the different nodes are and where we can find them</text>
-      </nodehandler>
-      <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Nodes" version="1.0">
-        <nodehandler class="textctrl_handler" icon="note" module="forms" name="Nodes and Sheets" version="1.0">
-          <text multiline="1" send_button="0">------------------------------------------------------------------------
---Character Sheets And Nodes
-------------------------------------------------------------------------
-
-Character sheets are the wonderful inventions that allow us to hold all the information we want about our characters and gaming worlds.  In OpenRPG they are made up of what we call &quot;Nodes.&quot;  These nodes are the building blocks for creating all manner of character sheets and can be rearranged into whatever form you wish.
-
-but to understand the nodes, we must first know how they work.  This chapter is dedicated to explaining the function of each node.  To get a new node, just find the one you want in the &quot;Templates&quot; tree and doubleclick on it.  That will put a fresh blank one in the gametree at the top.</text>
-        </nodehandler>
-        <nodehandler class="form_handler" icon="form" module="forms" name="Nodes" version="1.0">
-          <form height="700" width="400"/>
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name="The Text Node" version="1.0">
-            <text multiline="1" send_button="1">The Text Node is the very basic and most fundamental part of the character sheet.  It is where we store most of our important information.  To use a text node, first you must right click on it and press &quot;design.&quot;  This will bring up the text node's option's window.  In there you can choose whether the Text node only has one line or if it is a small text window, what it's title is, and whether it has a send button or not.  The Send button will send whatever is in the text node directly to the chat.</text>
-          </nodehandler>
-          <nodehandler class="listbox_handler" icon="gear" module="forms" name="List Box" version="1.0">
-            <list send_button="0" type="0">
-              <option selected="1" value="0">The List Box is a marvelous tool that allows you to have ...</option>
-              <option selected="0" value="0">dropdown menus and a variety of checklists and radio boxes.</option>
-              <option selected="0" value="0">To use a List box, right click on one that you created in your</option>
-              <option selected="0" value="0">gametree and press &quot;design&quot;.  this will bring up a window </option>
-              <option selected="0" value="0">where you can choose what type of list box it is and what </option>
-              <option selected="0" value="0">options are inside of it.  Simple as that!</option>
-            </list>
-          </nodehandler>
-          <nodehandler class="rpg_grid_handler" icon="grid" module="rpg_grid" name="Grid" version="1.0">
-            <grid autosize="1" border="1">
-              <row version="1.0">
-                <cell size="144">The Grid lets you keep tables</cell>
-                <cell size="138"></cell>
-              </row>
-              <row version="1.0">
-                <cell></cell>
-                <cell>like stats, or saving throws.</cell>
-              </row>
-              <row version="1.0">
-                <cell>You can arrange numbers</cell>
-                <cell></cell>
-              </row>
-              <row version="1.0">
-                <cell></cell>
-                <cell>more easily in a grid than</cell>
-              </row>
-              <row version="1.0">
-                <cell>you can with a text node.</cell>
-                <cell></cell>
-              </row>
-            </grid>
-            <macros>
-              <macro name=""/>
-            </macros>
-          </nodehandler>
-          <nodehandler class="webimg_handler" icon="image" module="forms" name="Image" version="1.0">
-            <link href="http://my.openrpg.com/images/logo200x60.jpg"/>
-          </nodehandler>
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name="Images allow for images. Just right click to provide the webpage addy they're at" version="1.0">
-            <text multiline="0" send_button="0"></text>
-          </nodehandler>
-          <nodehandler class="link_handler" icon="html" module="forms" name="OpenRPG.com link" version="1.0">
-            <link href="http://www.OpenRPG.com"/>
-          </nodehandler>
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-            <text multiline="0" send_button="0">you can change the link node's url by right clicking on it in the gametree</text>
-          </nodehandler>
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-            <text multiline="1" send_button="0">Now that we know what the individual nodes do, we need ways to group them together.  continue to the next page to learn about the different forms of groups.</text>
-          </nodehandler>
-        </nodehandler>
-        <nodehandler class="form_handler" icon="form" module="forms" name="containers" version="1.0">
-          <form height="700" width="700"/>
-          <nodehandler class="form_handler" icon="form" module="forms" name="Form" version="1.0">
-            <form height="400" width="400"/>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-              <text multiline="1" send_button="0">The Form is the basic and most used container of the lot.  It is what is able to hold all the other types of containers AND nodes.  Forms can also be placed within other containers as well, allowing for you to 'group up' a bunch of nodes in a form, then put that form as one page on a tabber. You can adjust the size by right clicking on a form in the game tree, pressing design, and adjusting the height and width</text>
-            </nodehandler>
-          </nodehandler>
-          <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-            <nodehandler class="splitter_handler" icon="divider" module="containers" name="Splitter" version="1.0">
-              <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-                <text multiline="0" send_button="0">text</text>
-              </nodehandler>
-              <nodehandler class="textctrl_handler" icon="note" module="forms" name="Text" version="1.0">
-                <text multiline="1" send_button="0">text</text>
-              </nodehandler>
-            </nodehandler>
-            <nodehandler class="textctrl_handler" icon="note" module="forms" name=" " version="1.0">
-              <text multiline="1" send_button="0">The splitter allows you to break a character sheet into segments, and have different datas side by side.  you can't have more than two single things inside a splitter, however you can put forms (or even other splitters!) inside a splitter.</text>
-            </nodehandler>
-          </nodehandler>
-          <nodehandler class="textctrl_handler" icon="note" module="forms" name="Folders" version="1.0">
-            <text multiline="1" send_button="0">Another node that is useful for keeping everything together is the folder. You can only view the stuff in it by using pretty print, but if you want to save a lot of work in one area, it is the thing you want to use.</text>
-          </nodehandler>
-        </nodehandler>
-      </nodehandler>
-    </nodehandler>
-    <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Character Sheets" version="1.0">
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Moving Characters from almost ANY Character Generator to here." version="1.0">
-        <text multiline="1" send_button="0">The following are stpes on how to move your character sheets from your favorite Character Generation program into OpenRPG.  It's very quick and clean cut.
-
-1) first, using your character generator, you convert your character to either txt format, or, preferably (if you have the ability) HTML format.
-
-2) Then, you go to wizards.put a text block into the gametree
-
-3) if you are using txt, select all, and copy.  if you are using HTML format, edit it using notepad, but don't change any of the HTML Program. then select all and copy
-
-4) now, going back into OpenRPG, right click on the text block you created and push 'edit'
-
-5) clear the text block of the few words of text that appear there then paste the copied info into by either rightclicking-paste or pressing 'ctrl v'
-
-6) then name your character in the Title then close the text block.  Finished
-
-no more need to create character sheets!  That simple and any time you want to see it, just doubleclick on the text node.</text>
-      </nodehandler>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Create Your Own Character" version="1.0">
-        <text multiline="1" send_button="0">((before we begin, see the character sheet repository:
-   http://openrpg.wrathof.com
-for pre-made character sheets.))
-
-
-Character Sheet creation (By Melanthos):
-
-So you wanna make a character sheet, huh? Well, follow these few short steps and you'll be on your way to Sheet Creation Godhood...or not. But don't blame me if you don't read this and can't make yourself a sheet. I'm going to guess you have a basic understanding of how the nodes work. I'll be using Harvester Incorporated(TM)'s Faction Wars(TM) as an example.
-
-First, you'll need a tabber. You can find it under containers in the templates node.  Click the + to the left of templates then click the plus next to containers.  Next double click the Create New Tabber.  Got it? Good. Now, you'll need a form. Forms are what we use to create each page of the tabber. They hold the rest of the nodes neatly, and open up - unlike groups, which cannot be opened in a sheet. To create a form double click on Create New Form.  You will notice two new nodes at the top of the game tree.
-
-
-        Tabbers, Forms, and Text-boxes, OH MY!
-
-Alright. Here is where I store the basics of the character. Since I don't like to scroll too much, I've broken down the information even more, so that I can fit into smaller tabbers and forms. First I'll create a second tabber. This will hold all the basic info - Level, Class, Player &amp; Character name, and a few other things. Since I've got 8 things I want to list, I've broken them up into 2 seperate groups, which have been put into different forms: General Info, and Specific Info. For simple things like name and level, I suggest using single-line text boxes. I've gone ahead and made 8 of these, naming each of them one of my 8 items and stuck them into their forms. Now that I've finished that, I'll put the two forms under my second tabber, and put that into my big form, &quot;General.&quot; I've done the same thing with the Attributes. Most of the sheet uses this principal, so I won't go into each form. Kinda redundant.
-
-
-                   List Boxes &amp; Die Creation
-
-Alright, for my second form, Vitals, I need some die-rollers. Since I don't need to change the rolls often, I've decided to use List Boxes to hold all my rolls. It's not too hard, and it's a really easy way to store rolls(It can be used for other things, but this is the best use I've found.): Now you don't have to type out those dice every time you wanna attack. First, I've created myself a List Box. Next, I'll decide how I want my list box to be shown: There are four choices. Drop Down, List Box, Radio Box, and Check List. Since I only need to roll one at a time, I've chosen Drop Down. But to show you how the Drop Down and Check List options work, I'll change things a bit and make a List Box and a Check List as well. When editing, make sure to click the &quot;Send Button&quot; box.
-
-
-        Drop Down
-
-The Drop Down is the least space- consuming of the List Box options. It's just like a single-line Text Box, except it holds more than one line. Click the arrow on the right to make it drop down, and click the die you want to roll. Then hit the Send button, and POOF! Your die has been rolled to the chat window.
-
-
-        Check List
-
-The Check List is a neat option. It lets you roll more than one die at a time. All you have to do is check the box next to the die (or dice) you want to roll, and POOF! Your dice have been rolled. Neat, eh?
-
-           Splitter
-
-Now what could these be used for, you wonder? Not much, but there are a few things. I've used it to hold my different abilities. It's easier for me to just see my choices than to flip between tabbers or scroll down and back up every few seconds.
-
-
-The rest is pretty easy. Just keep on with the things you've done so far, and in no time you'll be on your way to creating great sheets! Most of sheet creation is your personal preference. If you ask Woody, he might say something completely different than I might. Of course, you should make the sheets the way you want them. This is just to get you started. After you've got the basics of sheet making down, you can play around with sheets and nodes and things until you've got the sheet perfect for you. GOOD LUCK!!
-
-
---Melanthos, Founder &amp; Game Designer - Harvester Incorporated</text>
-      </nodehandler>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="Server Control" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="tabber_handler" icon="tabber" module="containers" name="Server Control" version="1.0">
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Running Your Own Server" version="1.0">
-        <text multiline="1" send_button="0">Creating a server:
-
-OpenRPG has come a long way since the dark ages of gaming.  With this new version we can now create servers on-the-fly!  No more black boxes or strange voodoo magic.  Just click on your &quot;Game Server&quot; menu, and select &quot;Start new server.&quot;  Fill in the options and away you go!  the server will appear instantly on the list.
-
-Of course, this won't provide you with all the same powers that the full server does.  While you can create a server on the short term, if you want to have a longterm dedicated server running which you can control, you'll want to run the OpenRPG Server in your start menu-programs-openrpg (or mplay_server.py in your openrpg folder).
-</text>
-      </nodehandler>
-      <nodehandler class="textctrl_handler" icon="note" module="forms" name="Running a Dedicated Server" version="1.0">
-        <text multiline="1" send_button="0">Well, maybe not any money in creating a server on this program, but there are definately perks to running one.  But to run one we must first understand what they do.
-
-A server is the mother for all of us on OpenRPG.  It runs all of our major commmands, keeps us all talking together, and hosts all the games on OpenRPG.  When you first connected to OpenRPG you had to choose a server from a list in the tracker, on the left.  Now let us put your name (or at least your computer's) out there so others can flock to you.
-
-For this we must return to your OS.  Go into your computer, into the OpenRPG folder.  In there, you will see a file marked:
-
-mplay_server.py
-
-You can also find it in your start menu, right next to the OpenRPG program itself.  Once you find it, (double)click on it.  The first thing that will come up is a python MSDOS window... It will first prompt on if you wish for your server to bee seen by the OpenRPG tracker list.  Press &quot;Y&quot; and hit enter (won't get anyone if we don't know it exists).  Next, it will prompt you for a name for your Server.  Write in &quot;Temporary Server&quot; and press enter.
-
-Now the window will start running the various server-y looking bits of code.  as soon as it is up and going, you will told the various commands that are available to the server.  The first one will be &quot;kill&quot;.  this is what you type into the MSDOS window to shut the server down.  &lt;b&gt;**IMPORTANT**&lt;/b&gt; if you shut down the server all rooms on it will close.  You don't want to shut it down if others are using it.
-
-The second command is the &quot;dump&quot; command.  This will list all the people on your server, as well as their ID number.  It really isn't important at this time but it will come in handy later.
-
-Broadcast is self explanitory.  The 'Announce' and 'Remove' features allow you to choose later on if your server can be seen on the tracker, or not.  Dump Groups gets the same info as Dump but does Groups instead of people.  And finally you can bring up this little list of commands at any time by typing 'help' or '?'.
-
-You can type these commands in any time in the python server window.  Go ahead and try 'help' or 'dump' and see what comes up.
-
-Alright!  That's it.  to access your server, run you OpenRPG program as normal (with the server MSDOS window in the background) and log onto your server as we had shown you in chapter 1.  This will come in handy if there are no Servers running and you wish to use OpenRPG with, perhaps your gaming buddies or maybe some underworld kingpins you need to 'have a talk' with.
-
-And From All of us at OpenRPG HQ, we wish you good gaming!</text>
-      </nodehandler>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="form_handler" icon="form" module="forms" name="The Map" version="1.0">
-    <form height="400" width="400"/>
-    <nodehandler class="textctrl_handler" icon="note" module="forms" name="Of Maps and Miniatures" version="1.0">
-      <text multiline="1" send_button="0">The Map:
-
-Now comes the hardest part of the tutorial.. describing how to use miniatures (minis)  and background images.  Well, the first step is to bring up the map.  Fortunately the new OpenRPG now loads maps differently than previous versions.  Likewise, it no longer seems to cause crashes for Windows users.  No longer will your client lag, lock up, or crash when loading images, large or small.  The entire map will now load in the background while you continue with your normal activity with the program.  Additionally, images, once loaded, will also be cached (stored) in RAM (up to 64; overflow is handled by randomly purging images within the cache to make room for new images).  That means switching back and forth between maps, in the same session, will result in instantaneous access to your map; no more waiting.  Furthermore, not only are your images loaded in the background, but they are loaded concurrently.  That means your map will be available faster than ever!  Hopefully these new innovations will lead to a renewed usage of the map.  Even modem users have indicated that using maps are now fun again!  Anyway, on with the tutorial.
-
-The Map Window is where most of your image viewing will reside.  In it you can manipulate miniatures and maps to give your players a well good idea of what your gaming world looks like.  In case you haven't guessed, it's the top-right window.  Looking at the Map Window, you'll see all of the basic operations needed to load an image and edit the map.  Let us attempt to load our first picture.  At the bottom of the map window you'll see a large box where you can type in text.  This is where you put  the Web-page Address for the image you wish.  Let's type in this URL/URI:  http://www.openrpg.com/images/mins/amazon.gif.  Notice that there are many great miniatures ready for you to use at OpenRPG's home-page.
-
-After you have typed it in press the &quot;add miniature&quot; button, sit back, and watch as it loads the beautiful amazonian woman (well, almost) into the map window.  Please note, however, all images need to be on web-pages and served up by a web server... you cannot load directly from your hard drive.  Well, you can, but no one else will be able to see it.  The reason being is because OpenRPG's client actually one giant web browser.
-
-Feel free to move it about, get a feel for how it works.  You'll see at the moment that the amazon seems to hop from grid square to grid square.  Well... if you're like me, you don't like being confined to grids or rules.  So let's get rid of that grid, shall we?  Again, looking at the map window, you will see a little red diamond thing.  They say it is a compass but it just looks like a flying fish to me.  Anyway.. click on that and it will bring up all the map settings.  In there you can change the size of the map, what color it is, or even load up a background on which all the mini's sit ((say, a dungeon map you drew or perhaps that picture of Britney Spears I know you have lying around)).  The thing we are interested in the most, though, will be the grid settings at the bottom.  As you can see, you can change the size of the grid and switch the grid from square(4 sided) to hex (6 sided).  You'll also be able to let mini's either abide by the grid, or become free from the black lined prison.  Let us turn off the &quot;snap to grid&quot; and press &quot;apply&quot;.  Also note that you can also make the grids disappear by making them match the background color, however, this is not the ideal way to do it as it still requires processing to draw and redraw the grid lines, even if they blend in without being visible.
-
-Now, go back into the map window and try moving your mini again.  You'll see that it now moves freely, and ignores those lines.  But ignoring them is not enough, did I hear you say?  You want them gone?  Ok.  Let's go back into the settings (the red star button) and this time change the grid size to zero.  Pressing 'apply' you will see that the grid has disappeared entirely from map.  Course, if you want it back, just go put in the size again (50 is default).  Feel free to make the grid size match your miniature and map scale.  Also, if you prefer to have the snap to grid, however, do not feel that it provides enough resolution in miniature movement, feel free to set the grid size to half or one forth of what your actual scale is.  This way, you miniatures will still fit nicely as well as be able to use the &quot;snap to grid&quot;, however, you'll better be able to stagger your miniatures or slightly offset tiled map sets.
-
-
-Tiled Map Sets:
-
-Often, DM's and GM's have the need to present a map to their players, however, they do not which to reveal the whole map and/or map section to their players.  After all, it does remove a lot of surprise if everything is right before the player's eyes.  Enter three new miniature options: &quot;Lock to back&quot;, &quot;Lock to front&quot;, &quot;Unlock Front/Back&quot;.  Previous to these options being available, either the whole map had to be loaded by changing the background image or players and DM's where forced to struggle when map sections were loaded as if they were miniatures.  Even though there was z-ordering options available, it was still tedious as miniatures would often disappear behind a map image.  Now, entire maps can be built before as game and loaded all at once, without giving away any surprises.
-
-By loading all of your map sections together as miniatures and marking each one visible or not visible, you can have great fun again with your maps!  Wait a minute, isn't this the same boat we were on before.  Well, enter the three new options.  Using the &quot;Lock to back&quot; option on each of your map sections, it will force them to always stay on the bottom of the z-order (stacking) of your miniatures.  That means, you'll now be able to change the z-order of your miniatures while all of them stay on top of your map image.  In other words, while the image is locked to the back of the z-order, it acts just like a background image should.  To restore a miniature to normal z-ordering, simply using the &quot;Unlock Front/Back&quot; option and it will once again be ordered just as any other miniature is.
-
-Wait a minute!  That's only two of the three options that you mentioned.  Well, the third option allows for even more flexibility in what DM's and GM's can present to their players, even on a visible map section.  Enter, the poor-man's fog-of-war.  By creating a &quot;mask&quot; in just about any shape you like (feel free to use transparent colors on gifs as needed), you can effectively lock the &quot;masking&quot; image to the top of the z-order which will hide a section of your visible map.  While this is still somewhat tedious, it will allow for much finer grain of control of what is and is not visible on your maps!
-
-
-Looking here, moving there:
-
-Directional markers have been a part of OpenRPG for some time now, however, there use is going to be better explained here.  If you notice, each miniature has a &quot;facing&quot; and &quot;heading&quot; available to it.  These serves not only to indicate a miniature's facing, but it's current direction of travel.  After all, you're quite able to turn your head and talk to your buddy while walking in a direction different than the one your head is pointed.  While this feature mostly serves board game players, RPGer's may find use in this too, especially when making canned maps.  Imagine, the 'ol evil cleric behind the podium with his back to you.  Now, you can make it clear on the map.  Oh wait, the cleric's minions do not have their back to you, rather, they are standing to his side and looking directly at him.  Closer look, and you see that the cleric too had his head turned to his minions in conversation.  Again, this can be expressed on your map.  Information like this makes it easier for the players to understand that the back-stab that they obviously want to do, won't be so easy to pull off.  All this, without having to verbally describe every little detail.  After all, isn't this what the maps is for?  Enjoy!
-
-
-Saving and Loading Your Map:
-
-Don't forget that you can save your hard work.  Once you have built your map, be sure to right click on the map and hit &quot;Save Map&quot;.  When you need it again, just do &quot;Load Map&quot;.  You don't even need to delete the contents of the previous map.  The client does all that for you!  Don't forget, if you load a previously viewed image, the caching will considerable speed the rate at which it's visible to you and your players.  Using a common set of miniatures helps to take advantage of this fact.
-
-The Other Modes:
-
-Now, you can also use something called map modes. This feature lets you draw, and use rulers and other fun stuff. To turn it on you right click in the map, go under switch modes and choose either whiteboard (drawing) or ruler (ruler with distance gauge). This can be useful if you ever needed to point out something to someone. To remove a line just right click on it and click remove, its as easy as that!
-</text>
-    </nodehandler>
-  </nodehandler>
-  <nodehandler class="textctrl_handler" icon="note" module="forms" name="Setting Up Rooms, Games, and Ignoring" version="1.0">
-    <text multiline="1" send_button="0">So now that you have your server, your custom character sheet, and have talked enough players into starting a game, you'll want to set up a private room so that you aren't disturbed by every wandering weirdo or Woody that happens upon your server (and be forwarned, you will find that various people will wander from server to server.  Do not be frightened, most of them are harmless).
-
-So, lets pull up your tracker window.  If you haven't done so already, be sure to connect to your server.  Once in there look onto the right side of the tracker window.  You will see some boxes marked &quot;Room name&quot;, &quot;Boot password&quot;, and if you check a little box, &quot;password&quot;.  the first two are rather self explanatory, and the last one is to lock your room in case you don't want to be bothered.  Be sure to tell your players what it is though.
-
-If you don't password protect a room you may get people wandering in looking for a game or just lurking watching your game.  If you don't want them in there you should first let them know and ask them to leave.  If they refuse your request then boot them.  It is very rude to boot someone from a non passworded room with out warning.
-
-Now that you have your custom built char sheet and you have talked enough players into starting a game, it's time to set up your own room.  Let's bring up that Tracker window again ((under the Game Server menu)).  Looking to the bottom left of it, you'll see a little box that allows you to type in your own room name and add a password if you like.  Let's start a room called &quot;Working on that darned fun tutorial&quot; and not put a password up.
-
-as you see the room you create will be exactly the same as the lobby, so there is nothing to worry about.  Lets load up our character sheet by right clicking on the &quot;Game Tree&quot; and pressing Insert file&quot;
-
-Now that we have our little char sheet we might as well show the world.  This can be done in one of three ways.  The first way is to right click on it and send it to other players (provided there are any).  This is how other players can get your sheet as they can't see it until you send it to them.
-
-The second way is to send it directly to the chat and let everyone see it there.  go ahead and do that by right clicking on the char sheet and pressing &quot;Send to Chat&quot;.  Now everyone gets to see it as it appears on their text chat window.
-
-the third option, Whisper to Player, is much the same as &quot;Send to chat&quot; only it sends it to a specific person or persons to see in their chat instead.
-
-Of course, there sometimes comes a day when there is a little spammonkey running about.  You know the type.  Just keeps askin pointless questions, hitting you with the same text, and generally making himself a nuesance.  Well fear not!  We have added in a brand new feature that allows you to ignore those unscrupulous people.  In the chat entry box just enter the command &quot;/i player_ID#&quot; and that will put a person on ignore (or toggle them back to un-ignore [you can also right click on the name and press toggle ignore]).  To get a list of ID's who are on your ignore list, just type &quot;/i&quot; alone, with nothing else.  You can even ignore/un-ignore multiple people at once, just put commas (( , )) between the names.  And that's it.  Ignore at your leasure.</text>
-  </nodehandler>
-  <nodehandler class="textctrl_handler" icon="note" module="forms" name="Other Features; Logs, Initiative, Upgrades" version="1.0">
-    <text multiline="1" send_button="0">Other features:
-
-It may seem a little odd that this seventh window is tucked behind some arrows, but I always thought this chapter was a little on the sinful side so over here it now lay.
-
-
-By getting here, you must have had quite a bit of time to read through the rest of the chapters.  Well, let's finish off with what few interesting toys we have left.
-
-To start with, lets talk about logging  To create a logfile, you can just press the disk button in the bottom right corner of the OpenRPG program, and choosing a name and place to save the file.  Badaboom!  a chatlog of everything you have seen is saved.
-
-Of course, most of you will want a way to have it automatically save a log each time it see's text.  To do that, type in &quot;/log to my_log&quot; (replacing &quot;my_log&quot; for what you want to call the file). It should automatically start logging to that filename (and will include the date in the filename you gave it).  if you want to turn it on or off later on, just type &quot;/log on&quot; or &quot;/log off&quot;
-
-Note: The chat logging system no longer appends a datestamp to the logfile
-specified.  This means that for the system to generate the logfile
-
-/foo/bar/gamelog-02-10-01.html for linux or \foo\bar\gamelog-02-10-01.html for windows
-
-Previously the user only had to have &quot;/foo/bar/gamelog&quot; entered as GameLogChatPrefix.
-To get the same logging pattern now, they'll have to set GameLogChatPrefix to
-the following:
-
-/foo/bar/gamelog-%d-%m-%y.html
-
-
---------------------------------------------------------------------------------
-
-The Initiative Tool.  A marvelous invention allowing DMs to organise and handle an otherwise chaotic scene that we know as combat.  Compatable with all versions of OpenRPG, it works incredibly simply.
-
-All that is needed is for the DM to press &quot;New Initiative&quot; in the tool, have all of the players and the DM to type in &quot;init [diceroll]&quot; (replacing 'diceroll' for your dice) and hit enter.  An example:
-
-init [1d10+6]
-
-once everyone has done that, the DM pulls up his tool again, hits refresh, and then sorts the list however he wants.  once it is sorted, he just hits &quot;send to chat&quot; and the person at the top of the list is then sent to the chat.
-
-Once all the people have been cycled through, it will say &quot;End of Init&quot; in the chat.  The DM just presses the &quot;Start new Initiative&quot; button one more time and away you go on another round of hacking!
-
-Now, if you are the player and not using the tool, you can even put your init command into a macro node (not a text node) and do it that way.  At the time of this publication there was a bug in the initiative code and the DM running the tool cannot use macro nodes for this.
-
-You can also set up your character sheets to be able to be rolled from.  To do it, you will just need a special node that you can find here:
-
-www.geocities.com/woody_j_dick/initiative.xml
-
-You can put it directly into OpenRPG by right clicking on your gametree, pressing &quot;Insert URL&quot; and putting that URL above into the box that appears.  Even the DM can use that node for rolling his initiatives.
-
-CAUTION!  Do not rename the node.  It will not work unless it has that name.
-
-
-The last button, &quot;Keep list&quot; is for Whitewolf players who need to use the list twice.  If you edit the list, and want to keep the edited copy, then just press that and it will save the list so all you need to do is hit refresh to get it back.
-
---------------------------------------------------------------------------------
-
-OpenRPG is a great program, no doubt about it.  And it's best quality is that it is opensourced, meaning anyone can look at the code and alter it to make it work better.  One such person, the one that compiled this tutorial no less, is going to capitalise on this free advertising to say a few quiet words about his webpage.
-
-www.geocities.com/woody_j_dick/OpenRPG.html
-
-The 8.3 Convention webpage, it offers many 'additional extras' That are not yet included in the main program.  Not only are the upgrades good for the current versions of OpenRPG, but it also retains a list of upgrades for previous versions, in case you want to go back and use that 'good ole' 9.4 or 9.6 client with the modern day servers.
-
-</text>
-  </nodehandler>
-</nodehandler>
--- a/orpg/templates/nodes/wizards.xml	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-
-<nodehandler class="static_handler" icon="flask" module="core" name="Wizards" status="useful">
-  <nodehandler class="file_loader" icon="d20" module="core" name="New Die Macro">
-    <file name="die_macro.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" module="core" name="New Group">
-    <file name="group.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="note" module="core" name="New Text Block">
-    <file name="text.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="grid" module="core" name="New Grid">
-    <file name="grid.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="html" module="core" name="New Link">
-    <file name="link.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="image" module="core" name="New Web Image">
-    <file name="image.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="browser" module="core" name="New Browser Link">
-    <file name="browser.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="gear" module="core" name="New Macro">
-    <file name="macro.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="compass" module="core" name="New Encounter">
-    <file name="encounter.xml"/>
-  </nodehandler>
-  <nodehandler class="file_loader" icon="gear" module="core" name="New Miniature Library">
-    <file name="minlib.xml"/>
-  </nodehandler>
-  <group_atts border="1" cols="1"/>
-  <nodehandler class="file_loader" icon="player" module="core" name="New Alias Library">
-    <file name="alias.xml"/>
-  </nodehandler>
-</nodehandler>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/tools/InterParse.py	Sat Apr 24 08:37:20 2010 -0500
@@ -0,0 +1,381 @@
+#!/usr/bin/env python
+# Copyright (C) 2000-2010 The OpenRPG Project
+#
+#        openrpg-dev@lists.sourceforge.net
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: InterParse.py
+# Author: 
+# Maintainer: Tyler Starke (Traipse)
+# Version:
+#   $Id: InterParse.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
+#
+# Description: InterParse = Interpretor Parser. This class parses all of the node referencing.
+#
+
+from orpg.orpgCore import component
+import re
+from orpg.tools.orpg_log import logger
+from wx import TextEntryDialog, ID_OK
+
+class InterParse():
+
+    def __init__(self):
+        pass
+
+    def Post(self, s, send=False, myself=False):
+        s = self.Normalize(s)
+        component.get('chat').set_colors()
+        component.get('chat').Post(s, send, myself)
+
+    def ParseLogic(self, s, node):
+        'Nodes now parse through ParsLogic. Easily add new parse rules right here!!'
+        s = self.NameSpaceE(s)
+        s = self.NameSpaceI(s, node)
+        s = self.NodeMap(s, node)
+        s = self.NodeParent(s, node.get('map'))
+        return s
+
+    def Normalize(self, s):
+        for plugin_fname in component.get('chat').activeplugins.keys():
+            plugin = component.get('chat').activeplugins[plugin_fname]
+            try: s = plugin.pre_parse(s)
+            except Exception, e:
+                if str(e) != "'module' object has no attribute 'post_msg'":
+                    logger.general(traceback.format_exc())
+                    logger.general("EXCEPTION: " + str(e))
+        if component.get('chat').parsed == 0:
+            s = self.NameSpaceE(s)
+            s = self.Node(s)
+            s = self.Dice(s)
+            s = self.Filter(s)
+            component.get('chat').parsed = 1
+        return s
+    
+    def Filter(self, s):
+        s = component.get('chat').GetFilteredText(s)
+        return s
+
+    def Node(self, s):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        #[a-zA-Z0-9 _\-\.]
+        reg = re.compile("(!@(.*?)@!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            newstr = self.Node(self.resolve_nodes(matches[i][1]))
+            s = s.replace(matches[i][0], newstr, 1)
+        return s
+
+    def Dice(self, s):
+        """Parses player input for embedded dice rolls"""
+        reg = re.compile("\[([^]]*?)\]")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            newstr = self.Unknown(matches[i])
+            qmode = 0
+            newstr1 = newstr
+            if newstr[0].lower() == 'q':
+                newstr = newstr[1:]
+                qmode = 1
+            if newstr[0].lower() == '#':
+                newstr = newstr[1:]
+                qmode = 2
+            try: newstr = component.get('DiceManager').proccessRoll(newstr)
+            except: pass
+            if qmode == 1:
+                s = s.replace("[" + matches[i] + "]", 
+                            "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
+            elif qmode == 2:
+                s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
+            else: s = s.replace("[" + matches[i] + "]", 
+                            "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
+        return s
+
+    def Unknown(self, s):
+	# Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY
+        newstr = "0"
+        reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            lb = "Replace '?' with: "
+            if len(matches[i][0]):
+                lb = matches[i][1] + "?: "
+            dlg = TextEntryDialog(component.get('chat'), lb, "Missing Value?")
+            dlg.SetValue('')
+            if matches[i][0] != '':
+                dlg.SetTitle("Enter Value for " + matches[i][1])
+            if dlg.ShowModal() == ID_OK: newstr = dlg.GetValue()
+            if newstr == '': newstr = '0'
+            s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1)
+            dlg.Destroy()
+        return s
+
+    def NameSpaceI(self, s, node):
+        reg = re.compile("(!=(.*?)=!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            tree_map = node.get('map').split('::')
+            root = self.get_node(tree_map[0])
+            find = matches[i][1].split('::')
+            names = root.getiterator('nodehandler')
+            for name in names:
+                if find[0] == name.get('name'):
+                    if name.get('class') == 'rpg_grid_handler': 
+                        newstr = self.NameSpaceGrid(find, name); break
+                    else: newstr = str(name.find('text').text); break
+                else: newstr = 'Invalid Reference!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.ParseLogic(s, name)
+        return s
+
+    def NameSpaceE(self, s):
+        reg = re.compile("(!&(.*?)&!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            find = matches[i][1].split('::')
+            root = find[0]
+            root = self.get_node(root)
+            names = root.getiterator('nodehandler')
+            for name in names:
+                if find[1] == name.get('name'):
+                    if name.get('class') == 'rpg_grid_handler': 
+                        newstr = self.NameSpaceGrid([find[1], find[2]], name); break
+                    else: newstr = str(name.find('text').text); break
+                else: newstr = 'Invalid Reference!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.ParseLogic(s, name)
+        return s
+
+    def NameSpaceGrid(self, s, node):
+        cell = tuple(s[1].strip('(').strip(')').split(','))
+        grid = node.find('grid')
+        rows = grid.findall('row')
+        col = rows[int(self.Dice(cell[0]))-1].findall('cell')
+        try: s = self.ParseLogic(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
+        except: s = 'Invalid Grid Reference!'
+        return s
+
+    def NodeMap(self, s, node):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        reg = re.compile("(!!(.*?)!!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            tree_map = node.get('map')
+            tree_map = tree_map + '::' + matches[i][1]
+            newstr = '!@'+ tree_map +'@!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.Node(s)
+            s = self.NodeParent(s, tree_map)
+        return s
+
+    def NodeParent(self, s, tree_map):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        reg = re.compile("(!#(.*?)#!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            ## Build the new tree_map
+            new_map = tree_map.split('::')
+            del new_map[len(new_map)-1]
+            parent_map = matches[i][1].split('::')
+            ## Backwards Reference the Parent Children
+            child_node = self.get_node('::'.join(new_map))
+            newstr = self.get_root(child_node, tree_map, new_map, parent_map)
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.Node(s)
+        return s
+
+    def get_root(self, child_node, tree_map, new_map, parent_map):
+        if child_node == 'Invalid Reference!': return child_node
+        roots = child_node.getchildren(); tr = tree_map.split('::')
+        newstr = ''
+        for root in roots:
+            try: t = new_map.index(root.get('name'))
+            except: t = 1
+            if parent_map[0] == root.get('name'):
+                newstr = '!@' + '::'.join(new_map[:len(tr)-t]) + '::' + '::'.join(parent_map) + '@!'
+        if newstr != '': return newstr
+        else:
+            del new_map[len(new_map)-1]
+            child_node = self.get_node('::'.join(new_map))
+            newstr = self.get_root(child_node, tree_map, new_map, parent_map)
+            return newstr
+
+    def get_node(self, s):
+        return_node = 'Invalid Reference!'
+        value = ""
+        path = s.split('::')
+        depth = len(path)
+        try: node = component.get('tree').tree_map[path[0]]['node']
+        except Exception, e: return return_node
+        return_node = self.resolve_get_loop(node, path, 1, depth)
+        return return_node
+
+    def resolve_get_loop(self, node, path, step, depth):
+        if step == depth: return node
+        else:
+            child_list = node.findall('nodehandler')
+            for child in child_list:
+                if step == depth: break
+                if child.get('name') == path[step]:
+                    node = self.resolve_get_loop(child, path, step+1, depth)
+            return node
+
+    def resolve_nodes(self, s):
+        self.passed = False
+        string = 'Invalid Reference!'
+        value = ""
+        path = s.split('::')
+        depth = len(path)
+        try: node = component.get('tree').tree_map[path[0]]['node']
+        except Exception, e: return string
+        if node.get('class') in ('dnd35char_handler', 
+                                "SWd20char_handler", 
+                                "d20char_handler", 
+                                "dnd3echar_handler"): string = self.resolve_cust_loop(node, path, 1, depth)
+        elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
+        else: string = self.resolve_loop(node, path, 1, depth)
+        return string
+
+    def resolve_loop(self, node, path, step, depth):
+        if step == depth: return self.resolution(node)
+        else:
+            child_list = node.findall('nodehandler')
+            for child in child_list:
+                if step == depth: break
+                if child.get('name') == path[step]:
+                    node = child
+                    step += 1
+                    if node.get('class') in ('dnd35char_handler', 
+                                            "SWd20char_handler", 
+                                            "d20char_handler", 
+                                            "dnd3echar_handler"): 
+                        string = self.resolve_cust_loop(node, path, step, depth)
+                    elif node.get('class') == 'rpg_grid_handler': 
+                        string = self.resolve_grid(node, path, step, depth)
+                    else: string = self.resolve_loop(node, path, step, depth)
+            return string
+
+    def resolution(self, node):
+        if self.passed == False:
+            self.passed = True
+            if node.get('class') == 'textctrl_handler': 
+                s = str(node.find('text').text)
+            else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
+        else: s = ''
+        s = self.ParseLogic(s, node)
+        return s
+
+    def resolve_grid(self, node, path, step, depth):
+        if step == depth:
+            return 'Invalid Grid Reference!'
+        cell = tuple(path[step].strip('(').strip(')').split(','))
+        grid = node.find('grid')
+        rows = grid.findall('row')
+        col = rows[int(self.Dice(cell[0]))-1].findall('cell')
+        try: s = self.ParseLogic(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
+        except: s = 'Invalid Grid Reference!'
+        return s
+
+    def resolve_cust_loop(self, node, path, step, depth):
+        s = 'Invalid Reference!'
+        node_class = node.get('class')
+        ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
+        if step == depth: self.resolution(node)
+        ##Build Abilities dictionary##
+        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities')
+        else: ab = node.find('abilities')
+        ab_list = ab.findall('stat'); pc_stats = {}
+
+        for ability in ab_list:
+            pc_stats[ability.get('name')] = ( 
+                    str(ability.get('base')), 
+                    str((int(ability.get('base'))-10)/2) )
+            pc_stats[ability.get('abbr')] = ( 
+                    str(ability.get('base')), 
+                    str((int(ability.get('base'))-10)/2) )
+
+        if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
+        else: ab = node.find('saves')
+        ab_list = ab.findall('save')
+        for save in ab_list:
+            pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
+            if save.get('name') == 'Fortitude': abbr = 'Fort'
+            if save.get('name') == 'Reflex': abbr = 'Ref'
+            if save.get('name') == 'Will': abbr = 'Will'
+            pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
+
+        if path[step].lower() == 'skill':
+            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
+            node = node.find('skills')
+            child_list = node.findall('skill')
+            for child in child_list:
+                if path[step+1].lower() == child.get('name').lower():
+                    if step+2 == depth: s = child.get('rank')
+                    elif path[step+2].lower() == 'check':
+                        s = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']'
+            return s
+
+        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: s = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
+            return s
+        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: s = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
+            return s
+        if path[step].lower() == 'attack':
+            if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat')
+            if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm':
+                bonus_text = '(Melee)'
+                bonus = node.find('attacks')
+                bonus = bonus.find('melee')
+                bonus = bonus.attrib; d = int(pc_stats['Str'][1])
+            elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r':
+                bonus_text = '(Ranged)'
+                bonus = node.find('attacks')
+                bonus = bonus.find('ranged')
+                bonus = bonus.attrib; d = int(pc_stats['Dex'][1])
+            for b in bonus:
+                d += int(bonus[b])
+            bonus = str(d)
+            if path[step+2] == None: s= bonus
+            else:
+                weapons = node.find('attacks')
+                weapons = weapons.findall('weapon')
+                for child in weapons:
+                    if path[step+2].lower() == child.get('name').lower():
+                        s = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']'
+            return s
+        elif pc_stats.has_key(path[step].title()):
+            if step+1 == depth: s = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
+            elif path[step+1].title() == 'Mod': s = pc_stats[path[step].title()][1]
+            elif path[step+1].title() == 'Check': s = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
+            return s
+        return s
+
+Parse = InterParse()
--- a/orpg/tools/aliaslib.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/aliaslib.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,12 +21,12 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: aliaslib.py,v 1.20 2007/08/09 05:23:21 digitalxero Exp $
+#   $Id: aliaslib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: nodehandler for alias.
 #
 
-__version__ = "$Id: aliaslib.py,v 1.20 2007/08/09 05:23:21 digitalxero Exp $"
+__version__ = "$Id: aliaslib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 from orpg.orpg_wx import *
 from orpg.orpgCore import component
@@ -35,6 +35,7 @@
 from orpg.dirpath import dir_struct
 from orpg.tools.validate import validate
 from orpg.tools.orpg_settings import settings
+from xml.etree.ElementTree import tostring, parse
 import re
 
 class AliasLib(wx.Frame):
@@ -174,7 +175,6 @@
         f.close()
 
     def OnMB_FileExportToTree(self, event):
-        #tree = component.get("tree")
         xml = '<nodehandler class="voxchat_handler" '
         xml += 'icon="player" '
         xml += 'module="voxchat" '
@@ -459,36 +459,30 @@
         self.Fit()
 
     def loadFile(self):
-        f = open(dir_struct["user"] + self.filename, "r")
-        data = f.read()
-        f.close()
-        self.alias = -1
-        self.filter = -1
-        xml_dom = component.get('xml').parseXml(data)
-        del data
-        aliases = xml_dom.getElementsByTagName("alias")
+        data = parse(dir_struct["user"] + self.filename)
+        xml_dom = data.getroot()
+        aliases = xml_dom.findall("alias")
         alist = []
         for alias in aliases:
-            if alias.hasAttribute("color"): color = alias.getAttribute("color")
+            if alias.get("color"): color = alias.get("color")
             else: color = 'Default'
-            aname = self.MakeSafeHTML(alias.getAttribute("name"))
+            aname = self.MakeSafeHTML(alias.get("name"))
             alist.append([aname, color])
         alist.sort()
         self.aliasList = alist
-        filters = xml_dom.getElementsByTagName("filter")
+        filters = xml_dom.findall("filter")
         flist = []
         self.regExList = []
         for filter in filters:
-            flist.append(filter.getAttribute("name"))
-            rules = filter.getElementsByTagName("rule")
+            flist.append(filter.get("name"))
+            rules = filter.findall("rule")
             sub = []
-            for rule in rules: sub.append([self.MakeSafeHTML(rule.getAttribute("match")), 
-                                        self.MakeSafeHTML(rule.getAttribute("sub"))])
+            for rule in rules: sub.append([self.MakeSafeHTML(rule.get("match")), 
+                                        self.MakeSafeHTML(rule.get("sub"))])
             self.regExList.append(sub)
         self.filterList = flist
-        xml_dom.unlink()
-        self.alias = -1
-        self.filter = -1
+        self.alias = 0
+        self.filter = 0
 
     def MakeSafeHTML(self, str):
         return str.replace("&amp;", "&").replace("&lt;", "<").replace("&quot;", '"').replace("&gt;", ">").replace("&#39;", "'")
@@ -496,7 +490,7 @@
         return str.replace("&", "&amp;").replace("<", "&lt;").replace('"', "&quot;").replace(">", "&gt;").replace("'", "&#39;")
     def ImportFromTree(self, xml_dom):
         oldfilename = self.filename
-        if xml_dom.getAttribute('name') == 'Alias Library':
+        if xml_dom.get('name') == 'Alias Library':
             dlg = wx.TextEntryDialog(self, "Please Name This Alias Lib", "New Alias Lib")
             if dlg.ShowModal() == wx.ID_OK:
                 self.filename = dlg.GetValue() + '.alias'
@@ -504,11 +498,11 @@
             else:
                 dlg.Destroy()
                 return
-        else: self.filename = xml_dom.getAttribute('name') + '.alias'
+        else: self.filename = xml_dom.get('name') + '.alias'
         settings.set_setting('aliasfile', self.filename[:-6])
         if oldfilename != self.filename: self.OnMB_FileSave(None, oldfilename)
         f = open(dir_struct["user"] + self.filename, "w")
-        f.write(xml_dom.toxml().replace('nodehandler', 'aliaslib').replace('voxchat.', ''))
+        f.write(tostring(xml_dom).replace('nodehandler', 'aliaslib').replace('voxchat.', ''))
         f.close()
         wx.CallAfter(self.loadFile)
 
@@ -689,8 +683,6 @@
         self.regExList[self.filterIdx] = list
 
     def FormatText(self, event):
-        #self.textColorBtn = wx.Button(self, wx.ID_ANY, "Color")
-        #self.textColorBtn.SetForegroundColour(wx.BLACK)
         id = event.GetId()
         txt = self.textWnd.GetValue()
         (beg, end) = self.textWnd.GetSelection()
--- a/orpg/tools/inputValidator.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/inputValidator.py	Sat Apr 24 08:37:20 2010 -0500
@@ -25,7 +25,7 @@
 # user input generated text.
 #
 
-__version__ = "$Id: inputValidator.py,v 1.11 2006/11/04 21:24:22 digitalxero Exp $"
+__version__ = "$Id: inputValidator.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
--- a/orpg/tools/orpg_log.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/orpg_log.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Dj Gilcrease
 # Maintainer:
 # Version:
-#   $Id: orpg_log.py,v 1.9 2007/05/06 16:43:02 digitalxero Exp $
+#   $Id: orpg_log.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: classes for orpg log messages
 #
@@ -102,13 +102,15 @@
         self.report = wx.Button(self, wx.ID_ANY, 'Bug Report')
         sizer = wx.GridBagSizer(hgap=1, vgap=1)
         sizer.Add(self.console, (0,0), span=(1,2), flag=wx.EXPAND)
-        sizer.Add(self.bt_clear, (1,0), flag=wx.ALIGN_LEFT)
-        sizer.Add(self.report, (1,1), flag=wx.ALIGN_LEFT)
+        sizer.Add(self.bt_clear, (1,0), span=(1,1), flag=wx.ALIGN_LEFT)
+        sizer.Add(self.report, (1,1), span=(1,1), flag=wx.ALIGN_RIGHT|wx.EXPAND)
         sizer.AddGrowableCol(0)
         sizer.AddGrowableRow(0)
         self.SetSizer(sizer)
+        #self.Layout()
         self.SetAutoLayout(True)
-        self.SetSize((450, 175))
+        self.SetSize((450, 275))
+        self.SetMinSize((450, 275))
         self.Bind(wx.EVT_CLOSE, self.Min) 
         self.Bind(wx.EVT_BUTTON, self.clear, self.bt_clear)
         self.Bind(wx.EVT_BUTTON, self.bug_report, self.report)
--- a/orpg/tools/orpg_settings.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/orpg_settings.py	Sat Apr 24 08:37:20 2010 -0500
@@ -183,14 +183,17 @@
 
     def dieroller_ok(self, changes):
         rm = component.get('DiceManager')
+        cur_die = rm.getRoller()
         try:
             rm.setRoller(changes)
             self.chat.SystemPost('You have changed your die roller to the <b>"' + rm.getRoller() + '"</b> roller.')
         except Exception, e:
-            print e
             rm.setRoller('std')
-            self.settings.change('dieroller', 'std')
-            self.chat.SystemPost('<b>"' + changes + '"</b> is an invalid roller. Setting roller to <b>"std"</b>')
+            rm.setRoller(cur_die)
+            self.settings.change('dieroller', cur_die)
+            self.chat.SystemPost('<b>"' + changes + '"</b> is an invalid roller.')
+            self.chat.InfoPost('Available die rollers: ' +str(rm.listRollers()) )
+            self.chat.InfoPost('You are using the <b>"' +cur_die+ '"</b> die roller.')
 
     def colortree_ok(self, changes):
         top_frame = component.get('frame')
--- a/orpg/tools/passtool.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/passtool.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Todd "Snowdog" Faris
 # Maintainer:
 # Version:
-#   $Id: passtool.py,v 1.9 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: passtool.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: password helper. remembers passwords so user
 #              doesn't have to type passwords over and over
--- a/orpg/tools/predTextCtrl.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/predTextCtrl.py	Sat Apr 24 08:37:20 2010 -0500
@@ -60,48 +60,17 @@
         return self.asciiChar
 
 
-# This class implements the tree structure to hold the words
-#
-# Defines:
-#    __init__(self,filename)
-#    updateMostCommon(self,target)
-#    setWord(self,wordText,priority,sumFlag)
-#    addWord(self,wordText)
-#    setWord(self,wordText)
-#    setWordPriority(self,wordText,priority)
-#    findWordNode(self,wordText) returns class Letter
-#    findWordPriority(self,wordText) returns int
-#    getPredition(self,k,cur) returns string
 class LetterTreeClass(object):
 
-    # Initialization subroutine.
-    #
-    # self : instance of self
-    # filename : name of word file to use
-    #
-    # returns None
-    #
-    # Purpose:  Constructor for LetterTree.  Basically, it initializes itself with a word file, if present.
     def __init__(self, singletonKey):
         if not isinstance(singletonKey, _SingletonKey):
             raise invalid_argument(_("Use LetterTree() to get access to singleton"))
 
-        self.rootNode = Letter("",None)                # rootNode is a class Letter
-        self.rootNode.children = {}                    # initialize the children list
-
+        self.rootNode = Letter("",None)                
+        self.rootNode.children = {} 
 
-    # updateMostCommon subroutine.
-    #
-    # self : instance of self
-    # target : class Letter that was updated
-    #
-    # Returns None
-    #
-    # Purpose:  Updates all of the parent nodes of the target, such that their mostCommon member
-    #           points to the proper class Letter, based on the newly updated priorities.
     def updateMostCommon(self, target):
-                                                # cur is a class Letter
-        prev = target.parentNode                # prev is a class Letter
+        prev = target.parentNode
         while prev:
             if prev.mostCommon is None:
                 prev.mostCommon = target
@@ -110,106 +79,44 @@
                     prev.mostCommon = target
             prev = prev.parentNode
 
-
+    def setWord(self,wordText,priority = 1,sumFlag = 0):
+        cur = self.rootNode                     
+        for ch in wordText:  
+            if cur.children.has_key(ch):
+                cur = cur.children[ch] 
+            else:  
+                newLetter = Letter(ch,cur)
+                if cur is self.rootNode:
+                    newLetter.parentNode = None
+                cur.children[ch] = newLetter
+                cur = newLetter  
+        if sumFlag: cur.priority += priority
+        else: cur.priority = priority 
+        self.updateMostCommon(cur) 
 
-    # setWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    # priority : integer priority to set the word
-    # sumFlag : if True, add the priority to the existing, else assign the priority
-    #
-    # Returns:  None
-    #
-    # Purpose:  Sets or increments the priority of a word, adding the word if necessary
-    def setWord(self,wordText,priority = 1,sumFlag = 0):
-        cur = self.rootNode                     # start from the root
-        for ch in wordText:                     # for each character in the word
-            if cur.children.has_key(ch):        # check to see if we've found a new word
-                cur = cur.children[ch]            # if we haven't found a new word, move to the next letter and try again
-            else:                               # in this clause, we're creating a new branch, as the word is new
-                newLetter = Letter(ch,cur)        # create a new class Letter using this ascii code and the current letter as a parent
-                if cur is self.rootNode:          # special case:  Others expect the top level letters to point to None, not self.rootNode
-                    newLetter.parentNode = None
-                cur.children[ch] = newLetter      #  add the new letter to the list of children of the current letter
-                cur = newLetter                   #  make the new letter the current one for the next time through
-
-        #  at this point, cur is pointing to the last letter of either a new or existing word.
-        if sumFlag: cur.priority += priority    #  if the caller wants to add to the existing (0 if new)
-        else: cur.priority = priority           #  else, the set the priority directly
-        self.updateMostCommon(cur)              # this will run back through the tree to fix up the mostCommon members
-
-    # addWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Used to add words known not to exist.
     def addWord(self,wordText):
         self.setWord(wordText,priority = 1)
 
-    # incWord subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Used to increment the priority of existing words and add new words.
-    # Note:     Generally, this method can be used instead of addWord.
-
     def incWord(self,wordText):
         self.setWord(wordText,priority = 1, sumFlag = 1)
 
-    # setWordPriority subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    # priority:  int that is the new priority
-    #
-    # Returns:  None
-    #
-    # Purpose:  Convenience method that wraps setWord.  Sets existing words to priority or adds new words with priority = priority
-
     def setWordPriority(self,wordText,priority):
         self.setWord(wordText,priority = priority)
 
 
-    # findWordNode subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  class Letter or None if word isn't found.
-    #
-    # Purpose:  Given a word, it returns the class Letter node that corresponds to the word.  Used mostly in prep for a call to
-    #           getPrediction()
-
-    def findWordNode(self,wordText):         #returns class Letter that represents the last letter in the word
-        cur = self.rootNode                  # start at the root
-        for ch in wordText:                  # move through each letter in the word
-            if cur.children.has_key(ch):     # if the next letter exists, make cur equal that letter and loop
+    def findWordNode(self,wordText):  
+        cur = self.rootNode 
+        for ch in wordText: 
+            if cur.children.has_key(ch):
                 cur = cur.children[ch]
-            else: return None                # return None if letter not found
-        return cur                           # return cur, as this points to the last letter if we got this far
-
-
-    # findWordPriority subroutine.
-    #
-    # self : instance of self
-    # wordText : string representing word to add
-    #
-    # Returns:  Int representing the word's priority or 0 if not found.
-    #
-    # Purpose:  Returns the priority of the given word
+            else: return None  
+        return cur  
 
     def findWordPriority(self,wordText):
 
-        cur = self.findWordNode(wordText)    #  find the class Letter node that corresponds to this word
-        if cur: return cur.priority          #  if it was found, return it's priority
-        else: return 0                       #  else, return 0, meaning word not found
+        cur = self.findWordNode(wordText) 
+        if cur: return cur.priority
+        else: return 0 
 
     def printTree(self, current=None):
         letters = []
@@ -222,50 +129,18 @@
                 letters.append(m)
         return letters
 
-    # getPrediction subroutine.
-    #
-    # self : instance of self
-    # k : ASCII char that was typed
-    # cur : class Letter that points to the current node in LetterTree
-    #
-    # Returns:  The predicted text or "" if none found
-    #
-    # Purpose:  This is the meat and potatoes of data structure.  It takes the "current" Letter node and the next key typed
-    #           and returns it's guess of the rest of the word, based on the highest priority letter in the rest of the branch.
     def getPrediction(self,k,cur):
 
-        if cur.children.has_key(k) :                            #  check to see if the key typed is a sub branch
-                                                                #  If so, make a prediction.  Otherwise, do the else at the bottom of
-                                                                #  the method (see below).
-
-            cur = cur.children[k]                               #  set the cur to the typed key's class Letter in the sub-branch
-
-            backtrace = cur.mostCommon                          # backtrace is a class Letter.  It's used as a placeholder to back trace
-                                                                # from the last letter of the mostCommon word in the
-                                                                # sub-tree up through the tree until we meet ourself at cur.  We'll
-                                                                # build the guess text this way
-
-            returnText = ""                                     # returnText is a string.  This will act as a buffer to hold the string
-                                                                # we build.
-
-            while cur is not backtrace:                         #  Here's the loop.  We loop until we've snaked our way back to cur
-
-                returnText = backtrace.asciiChar + returnText   #  Create a new string that is the character at backtrace + everything
-                                                                #  so far.  So, for "tion"  we'll build "n","on","ion","tion" as we ..
-
-                backtrace = backtrace.parentNode                #  ... climb back towards cur
-
-            return returnText                                   #  And, having reached here, we've met up with cur, and returnText holds
-                                                                #  the string we built.  Return it.
-
-        else:                                                   #  This is the else to the original if.
-                                                                #  If the letter typed isn't in a sub branch, then
-                                                                #  the letter being typed isn't in our tree, so
-            return ""                                           #  return the empty string
-
-
-#  End of class LetterTree!
-
+        if cur.children.has_key(k) : 
+            cur = cur.children[k] 
+            backtrace = cur.mostCommon
+            returnText = ''
+            while cur is not backtrace: 
+                returnText = backtrace.asciiChar + returnText
+                backtrace = backtrace.parentNode 
+            return returnText 
+        else: 
+            return "" 
 
 
 class _SingletonKey(object):
@@ -277,62 +152,24 @@
 __key = _SingletonKey()
 LetterTree = LetterTreeClass(__key)
 
-# This class extends wx.TextCtrl
-#
-# Extends:  wx.TextCtrl
-#
-# Overrides:
-#    wx.TextCtrl.__init__(self,parent,id,value,size,style,name)
-#    wx.TextCtrl.OnChar(self,Event)
-#
-# Defines:
-#    findWord(self,insert,st)
+
 class predTextCtrl(ExpandoTextCtrl):
 
-    # Initialization subroutine.
-    #
-    # self : instance of self
-    # parent:  reference to parent window (wxWindow, me-thinks)
-    # id:      new Window Id, default to -1 to create new (I think: see docs for wxPython)
-    # value:   String that is the initial value the control holds, defaulting to ""
-    # size:    defaults to wx.DefaultSize
-    # style:   defaults to 0
-    # name:    defaults to "text"
-    # keyHook: must be a function pointer that takes self and a GetKeyCode object
-    # validator: defaults to None
-    #
-    # Note:  These parameters are essentially just passed back to the native wx.TextCtrl.
-    #        I basically just included (stole) enough of them from chatutils.py to make
-    #        it work.  Known missing args are pos and validator, which aren't used by
-    #        chatutils.py.
-    #
-    # Returns:  None
-    #
-    # Purpose:  Constructor for predTextCtrl.  Calls wx.TextCtrl.__init__ to get default init
-    #           behavior and then inits a LetterTree and captures the parent for later use in
-    #           passing events up the chain.
     def __init__(self, parent, id = -1, value = "", size = (30,30), style = 0, name = "text", keyHook = None, validator=None):
-
-        #  Call super() for default behavior
         if validator:
             ExpandoTextCtrl.__init__(self, parent, id=id, value=value, size=size, style=style, name=name, validator=validator )
         else:
             ExpandoTextCtrl.__init__(self, parent, id=id, value=value, size=size, style=style, name=name)
 
 
-        self.tree = LetterTree      #  Instantiate a new LetterTree.
-        #  TODO:  make name of word file an argument.
-        self.parent = parent           #  Save parent for later use in passing KeyEvents
-        self.cur = self.tree.rootNode  # self.cur is a short cut placeholder for typing consecutive chars
-                                       # It may be vestigal
-        self.keyHook = keyHook         #  Save the keyHook passed in
+        self.tree = LetterTree 
+        self.parent = parent  
+        self.cur = self.tree.rootNode  
+        self.keyHook = keyHook  
         ExpandoTextCtrl._wrapLine = self._wrapLine
         
 
     def _wrapLine(self, line, dc, width):
-        # Estimate where the control will wrap the lines and
-        # return the count of extra lines needed.
-        # Re writes ExpandoTextCtrl _wrapLine function
         pte = dc.GetPartialTextExtents(line)
         width -= wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X)
         idx = 0
@@ -342,9 +179,7 @@
         while idx < len(pte):
             if line[idx] == ' ': spc = idx
             if pte[idx] - start > width:
-                # we've reached the max width, add a new line
                 count += 1
-                # did we see a space? if so restart the count at that pos
                 if spc != -1:
                     idx = spc + 1
                     spc = -1
@@ -353,31 +188,7 @@
                 idx += 1
         return count
 
-    # findWord subroutine.
-    #
-    # self :  instance of self
-    # insert: index of last char in st
-    # st :    string from insert to the left
-    #
-    # Note:  This implementation is about the third one for this method.  Originally,
-    #        st was an arbitrary string and insert was the point within
-    #        this string to begin looking left.  Since, I finally got it
-    #        to work right as it is around 2 in the morning, I'm not touching it, for now.
-    #
-    # Returns:  String that is the word or "" if none found.  This generally doesn't
-    #           happen, as st usually ends in a letter, which will be returned.
-    #
-    # Purpose:  This function is generally used to figure out the beginning of the
-    #           current word being typed, for later use in a LetterTree.getPrediction()
     def findWord(self, insert, st):
-
-    #  Good luck reading this one.  Basically, I started out with an idea, and fiddled with the
-    #  constants as best I could until it worked.  It's not a piece of work of which I'm too
-    #  proud.  Basically, it's intent is to check each character to the left until it finds one
-    #  that isn't a letter.  If it finds such a character, it stops and returns the slice
-    #  from that point to insert.  Otherwise, it returns the whole thing, due to begin being
-    #  initialized to 0
-
         begin = 0
         for offset in range(insert - 1):
             if st[-(offset + 2)] not in string.ascii_letters:
@@ -385,210 +196,96 @@
                 break
         return st[begin:insert]
 
-
-    # OnChar subroutine.
-    #
-    # self :  instance of self
-    # event:  a GetKeyCode object
-    #
-    # Returns:  None
-    #
-    # Purpose:  This function is the key event handler for predTextCtrl.  It handles what it
-    #           needs to and passes the event on to it's parent's OnChar method.
     def OnChar(self,event):
 
-        #  Before we do anything, call the keyHook handler, if not None
-        #    This is currently used to implement the typing/not_typing messages in a manner that
-        #         doesn't place the code here.  Maybe I should reconsider that.  :)
         if(self.keyHook):
-            if self.keyHook(event) == 1:   #  if the passed in keyHook routine returns a one, it wants no predictive behavior
+            if self.keyHook(event) == 1: 
                 self.parent.OnChar(event)
                 return
-
-        #  This bit converts the GetKeyCode() return (int) to a char if it's in a certain range
         asciiKey = ""
         if (event.GetKeyCode() < 256) and (event.GetKeyCode() > 19):
             asciiKey = chr(event.GetKeyCode())
-
-        if asciiKey == "":                              #  If we didn't convert it to a char, then process based on the int GetKeyCodes
-            if  event.GetKeyCode() == wx.WXK_TAB:       #  We want to hook tabs to allow the user to signify acceptance of a
-                                                        #  predicted word.
-                #  Handle Tab key
-                fromPos = toPos = 0                     # get the current selection range
+        if asciiKey == "":  
+            if  event.GetKeyCode() == wx.WXK_TAB: 
+                fromPos = toPos = 0 
                 (fromPos,toPos) = self.GetSelection()
-                if (toPos - fromPos) == 0:              # if there is no selection, pass tab on
+                if (toPos - fromPos) == 0:  
                     self.parent.OnChar(event)
                     return
-                else:                                      #  This means at least one char is selected
-                    self.SetInsertionPoint(toPos)          #  move the insertion point to the end of the selection
-                    self.SetSelection(toPos,toPos)         #  and set the selection to no chars
-                                                           #  The prediction, if any, had been inserted into the text earlier, so
-                                                           #  moving the insertion point to the spot directly afterwards is
-                                                           #  equivalent to acceptance.  Without this, the next typed key would
-                                                           #  clobber the prediction.
-
-                    return                                 #  Don't pass tab on in this case
+                else:   
+                    self.SetInsertionPoint(toPos)  
+                    self.SetSelection(toPos,toPos) 
+                    return
 
-            elif event.GetKeyCode() == wx.WXK_RETURN:      #  We want to hook returns, so that we can update the word list
-                st = self.GetValue()                       #  Grab the text from the control
-                newSt = ""                                 #  Init a buffer
-                #  This block of code, by popular demand, changes the behavior of the control to ignore any prediction that
-                #  hasn't been "accepted" when the enter key is struck.
-                (startSel,endSel) = self.GetSelection()    #  get the curren selection
-
-                #
-                # Start update
-                # Changed the following to allow for more friendly behavior in
-                # a multilined predTextCtrl.
-                #
-                # front = st[:startSel]                      #  Slice off the text to the front of where we are
-                # back = st[endSel:]                         #  Slice off the text to the end from where we are
-                # st = front + back                          #  This expression creates a string that get rid 
-                                                             #  of any selected text.
-                # self.SetValue(st)
-
+            elif event.GetKeyCode() == wx.WXK_RETURN: 
+                st = self.GetValue() 
+                newSt = "" 
+                (startSel,endSel) = self.GetSelection() 
                 self.Remove( startSel, endSel )
                 st = string.strip( self.GetValue() )
-                #
-                # End update
-                #
-
-                #  this loop will walk through every character in st and add it to
-                #  newSt if it's a letter.  If it's not a letter, (e.g. a comma or
-                #  hyphen) a space is added to newSt in it's place.
                 for ch in st:
                     if ch not in string.ascii_letters:
                         newSt += " "
                     else:
                         newSt += ch
-                #  Now that we've got a string of just letter sequences (words) and spaces
-                #  split it and to a LetterTree.incWord on the lowercase version of it.
-                #  Reminder:  incWord will increment the priority of existing words and add
-                #  new ones
                 for aWord in string.split(newSt):
                     self.tree.incWord(string.lower(aWord))
-                self.parent.OnChar(event) #  Now that all of the words are added, pass the event and return
+                self.parent.OnChar(event)
                 return
 
-            #  We want to capture the right arrow key to fix a slight UI bug that occurs when one right arrows
-            #  out of a selection.  I set the InsertionPoint to the beginning of the selection.  When the default
-            #  right arrow event occurs, the selection goes away, but the cursor is in an unexpected location.
-            #  This snippet fixes this behavior and then passes on the event.
             elif event.GetKeyCode() == wx.WXK_RIGHT:
                 (startSel,endSel) = self.GetSelection()
                 self.SetInsertionPoint(endSel)
                 self.parent.OnChar(event)
                 return
 
-            #  Ditto as wx.WXK_RIGHT, but for completeness sake
             elif event.GetKeyCode() == wx.WXK_LEFT:
                 (startSel,endSel) = self.GetSelection()
                 self.SetInsertionPoint(startSel)
                 self.parent.OnChar(event)
                 return
             else:
-                #   Handle any other non-ascii events by calling parent's OnChar()
-                self.parent.OnChar(event)     #Call super.OnChar to get default behavior
+
+                self.parent.OnChar(event) 
                 return
         elif asciiKey in string.ascii_letters:
-           #  This is the real meat and potatoes of predTextCtrl.  This is where most of the
-           #  wx.TextCtrl logic is changed.
-            (startSel,endSel) = self.GetSelection()                 #  get the curren selection
-            st = self.GetValue()                                    #  and the text in the control
-            front = st[:startSel]                                   #  Slice off the text to the front of where we are
-            back = st[endSel:]                                      #  Slice off the text to the end from where we are
-            st = front + asciiKey + back                            #  This expression creates a string that will insert the
-                                                                    #  typed character (asciiKey is generated at the
-                                                                    #  beginning of OnChar()) into the text.  If there
-                                                                    #  was text selected, that text will not be part
-                                                                    #  of the new string, due to the way front and back
-                                                                    #  were sliced.
+            (startSel,endSel) = self.GetSelection() 
+            st = self.GetValue() 
+            front = st[:startSel]
+            back = st[endSel:]  
+            st = front + asciiKey + back
+            insert = startSel + 1   
+            curWord = ""   
+            if (len(back) == 0) or (back[0] not in string.ascii_letters):
 
-            insert = startSel + 1                                   #  creates an int that denotes where the new InsertionPoint
-                                                                    #  should be.
-            curWord = ""                                            #  Assume there's a problem with finding the curWord
-            if (len(back) == 0) or (back[0] not in string.ascii_letters): #  We should only insert a prediction if we are typing
-                                                                    #  at the end of a word, not in the middle.  There are
-                                                                    #  three cases: we are typing at the end of the string or
-                                                                    #  we are typing in the middle of the string and the next
-                                                                    #  char is NOT a letter or we are typing in the middle of the
-                                                                    #  string and the next char IS a letter.  Only the former two
-                                                                    #  cases denote that we should make a prediction
-                                                                    #  Note:  The order of the two logical clauses here is important!
-                                                                    #         If len(back) == 0, then the expression back[0] will
-                                                                    #         blow up with an out of bounds array subscript.  Luckily
-                                                                    #         the or operator is a short-circuit operator and in this
-                                                                    #         case will only evaluate back[0] if len(back) != 0, in
-                                                                    #         which we're safely in bounds.
+                curWord = self.findWord(insert,front + asciiKey) 
+            else: 
+                self.parent.OnChar(event)
+                return
 
-                curWord = self.findWord(insert,front + asciiKey)    #  Now that we know we're supposed to make a prediction,
-                                                                    #  let's find what word root to use in our prediction.
-                                                                    #  Note:  This is using the confusing findWord method.  I
-                                                                    #         send it insert and the text from the beginning
-                                                                    #         of the text through the key just entered.  This is
-                                                                    #         NOT the original usage, but it does work.  See
-                                                                    #         findWord() for more details.
-
-            else:                                                   #  Here, we've found we're in the middle of a word, so we're
-                                                                    #  going to call the parent's event handler.
+            if curWord == "":  
                 self.parent.OnChar(event)
                 return
 
-            if curWord == "":                                       #  Here, we do a quick check to make sure we have a good root
-                                                                    #  word.  If not, allow the default thing to happen.  Of course,
-                                                                    #  now that I'm documenting this, it occurs to me to wonder why
-                                                                    #  I didn't do the same thing I just talked about.  Hmmmmmm.
-
-                self.parent.OnChar(event)                           # we're done here
+            self.cur = self.tree.findWordNode(string.lower(curWord[:-1])) 
+            if self.cur is None:
+                self.parent.OnChar(event)  
                 return
-
-            self.cur = self.tree.findWordNode(string.lower(curWord[:-1]))  #  Still with me?  We're almost done.  At this point, we
-                                                                           #  need to convert our word string to a Letter node,
-                                                                           #  because that's what getPrediction expects.  Notice
-                                                                           #  that we're feeding in the string with the last
-                                                                           #  char sliced off.  For developmentally historical
-                                                                           #  reasons, getPrediction wants the node just before
-                                                                           #  the typed character and the typed char separately.
-
-
-            if self.cur is None:
-                self.parent.OnChar(event)                                  # if there's no word or no match, we're done
-                return
-
-
-            # get the prediction
-            predictText = self.tree.getPrediction(string.lower(asciiKey),self.cur)     #  This is the big prediction, as noted above
-                                                                                       #  Note the use of string.lower() because we
-                                                                                       #  keep the word list in all lower case,but we
-                                                                                       #  want to be able to match any capitalization
+            predictText = self.tree.getPrediction(string.lower(asciiKey),self.cur) 
 
             if predictText == "":
-                self.parent.OnChar(event)                                              # if there's no prediction, we're done
+                self.parent.OnChar(event)  
                 return
-
-            #  And now for the big finale.  We're going to take the string st
-            #  we created earlier and insert the prediction right after the
-            #  newly typed character.
-            front = st[:insert]                                 #  Grab a new front from st
-            back = st[insert:]                                  #  Grab a new back
-
-            st = front + predictText + back                     #  Insert the prediction
+            front = st[:insert] 
+            back = st[insert:]
 
-            self.SetValue(st)                                   #  Now, overwrite the controls text with the new text
-            self.SetInsertionPoint(insert)                      #  Set the proper insertion point, directly behind the
-                                                                #  newly typed character and directly in front of the
-                                                                #  predicted text.
+            st = front + predictText + back 
+            self.SetValue(st)   
+            self.SetInsertionPoint(insert) 
+            self.SetSelection(insert,insert+len(predictText))
+            return   
+        else:
 
-            self.SetSelection(insert,insert+len(predictText))   #  Very important!  Set the selection to encompass the predicted
-                                                                #  text.  This way, the user can ignore the prediction by simply
-                                                                #  continuing to type.  Remember, if the user wants the prediction
-                                                                #  s/he must strike the tab key at this point.  Of course, one could
-                                                                #  just use the right arrow key as well, but that's not as easy to
-                                                                #  reach.
+            self.parent.OnChar(event) 
+            return
 
-            return                                              #  Done!  Do NOT pass the event on at this point, because it's all done.
-        else:
-            #   Handle every other non-letter ascii (e.g. semicolon) by passing the event on.
-            self.parent.OnChar(event)     #Call super.OnChar to get default behavior
-            return
-#  End of class predTextCtrl!
--- a/orpg/tools/pubsub.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/pubsub.py	Sat Apr 24 08:37:20 2010 -0500
@@ -24,7 +24,7 @@
 
 :Author:      Oliver Schoenborn
 :Since:       Apr 2004
-:Version:     $Id: pubsub.py,v 1.8 2006/06/11 00:12:59 RD Exp $
+:Version:     $Id: pubsub.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 :Copyright:   \(c) 2004 Oliver Schoenborn
 :License:     wxWidgets
 """
--- a/orpg/tools/rgbhex.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/rgbhex.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: rgbhex.py,v 1.10 2007/02/19 16:33:20 digitalxero Exp $
+#   $Id: rgbhex.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: rgb to hex utility
 
--- a/orpg/tools/scriptkit.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/scriptkit.py	Sat Apr 24 08:37:20 2010 -0500
@@ -21,7 +21,7 @@
 # Author: Ted Berg
 # Maintainer:
 # Version:
-#   $Id: scriptkit.py,v 1.15 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: scriptkit.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: Class that contains convenience methods for various operations.  Was created with the purpose
 #       of exposing a simple API to users of an as yet uncreated scripting interface.
--- a/orpg/tools/server_probe.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/server_probe.py	Sat Apr 24 08:37:20 2010 -0500
@@ -23,7 +23,7 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: server_probe.py,v 1.10 2006/11/04 21:24:22 digitalxero Exp $
+#   $Id: server_probe.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
 #
 # Description: This is a periodic maintenance script for removing
 # Unresponsive servers from the meta list.
--- a/orpg/tools/toolBars.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/toolBars.py	Sat Apr 24 08:37:20 2010 -0500
@@ -25,7 +25,7 @@
 #
 #
 
-__version__ = "$Id: toolBars.py,v 1.13 2006/11/04 21:24:22 digitalxero Exp $"
+__version__ = "$Id: toolBars.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
 
 
 ##
--- a/orpg/tools/validate.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/orpg/tools/validate.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,11 +1,3 @@
-# file: config_files.py
-#
-# Author: Todd Faris (Snowdog)
-# Date:   5/10/2005
-#
-# Misc. config file service methods
-#
-
 from orpg.dirpath import dir_struct
 import os
 from orpg.orpgCore import component
--- a/plugins/bcg/tok_dialogs.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,531 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/min_dialogs.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: min_dialogs.py,v 1.27 2006/11/13 02:23:16 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-
-##-----------------------------
-## token List Panel
-##-----------------------------
-
-from tokens import *
-
-class min_list_panel(wx.Dialog):
-
-    def __init__(self, parent,layers, log, pos =(-1,-1)):
-        wx.Dialog.__init__(self,  parent,-1, log,pos = (-1,-1), size = (785,175), style=wx.RESIZE_BORDER)
-        listID = wx.NewId()
-        self.parent = parent
-        self.min = layers['tokens'].tokens
-        self.grid = layers['grid']
-        self.layers = layers
-        self.listID = listID
-        list_sizer = wx.BoxSizer(wx.VERTICAL)
-        self.list_sizer = list_sizer
-        listctrl = wx.ListCtrl(self, listID, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
-        self.listctrl = listctrl
-        self.Centre(wx.BOTH)
-        self.log = log
-        self.list_sizer.Add(self.listctrl,1,wx.EXPAND)
-        self.listctrl.InsertColumn(0,"POS    ")
-        self.listctrl.InsertColumn(0,"LOCKED")
-        self.listctrl.InsertColumn(0,"HEADING")
-        self.listctrl.InsertColumn(0,"FACING")
-        self.listctrl.InsertColumn(0,"LABEL")
-        self.listctrl.InsertColumn(0,"PATH")
-        self.listctrl.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(2, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(4, wx.LIST_AUTOSIZE_USEHEADER)
-        self.listctrl.SetColumnWidth(5, wx.LIST_AUTOSIZE_USEHEADER)
-        self.list_sizer.Add(wx.Button(self, wx.ID_OK, "DONE"),0,wx.ALIGN_CENTER)
-        self.refresh()
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-        self.listctrl.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick, id=listID)
-        self.listctrl.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
-        self.listctrl.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-        self.SetSizer(self.list_sizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-    def OnRightClick(self,event):
-        if self.listctrl.GetSelectedItemCount() > 0:
-            menu = wx.Menu()
-            lPopupID1 = wx.NewId()
-            lPopupID2 = wx.NewId()
-            lPopupID3 = wx.NewId()
-            menu.Append(lPopupID1, "&Edit")
-            menu.Append(lPopupID2, "&Delete")
-            menu.Append(lPopupID3, "To &Gametree")
-            self.Bind(wx.EVT_MENU, self.onEdit, id=lPopupID1)
-            self.Bind(wx.EVT_MENU, self.onDelete, id=lPopupID2)
-            self.Bind(wx.EVT_MENU, self.onToGametree, id=lPopupID3)
-            self.PopupMenu(menu, cmpPoint(self.x, self.y))
-            menu.Destroy()
-        event.Skip()
-
-    def refresh(self):
-        self.SetMinSize((600,175));
-        for m in self.min:
-            self.listctrl.InsertStringItem(self.min.index(m),self.min[self.min.index(m)].path)
-            self.listctrl.SetStringItem(self.min.index(m),1,self.min[self.min.index(m)].label)
-            self.listctrl.SetStringItem(self.min.index(m),2,`self.min[self.min.index(m)].heading`)
-            #self.listctrl.SetStringItem(self.min.index(m),3,`self.min[self.min.index(m)].face`)
-            self.listctrl.SetStringItem(self.min.index(m),4,`self.min[self.min.index(m)].locked`)
-            self.listctrl.SetStringItem(self.min.index(m),5,`self.min[self.min.index(m)].pos`)
-            oldcolumnwidth = self.listctrl.GetColumnWidth(0)
-            self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-            if oldcolumnwidth < self.listctrl.GetColumnWidth(0): self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-            else: self.listctrl.SetColumnWidth(0, oldcolumnwidth)
-        self.list_sizer=self.list_sizer
-
-    def onEdit(self,event):
-        min_list = []
-        min_index = []
-        loop_count = 0
-        item =-1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            min_list.append(self.min[item])
-            min_index.append(item-loop_count+1)
-        if len(min_list) > 0: dlg = min_list_edit_dialog(self.parent,min_index, min_list,self.layers)
-        if dlg.ShowModal() == wx.ID_OK: pass
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def onDelete(self,event):
-        loop_count = 0
-        item = -1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            self.layers["tokens"].del_token(self.min[item-loop_count+1])
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def onToGametree(self,event):
-        min_list = []
-        min_index = []
-        loop_count = 0
-        item =-1
-        while True:
-            loop_count += 1
-            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
-            if item == -1: break
-            min_list.append(self.min[item])
-            min_index.append(item-loop_count+1)
-        if len(min_list) > 0:
-            for sel_rmin in min_list:
-             #############
-                min_xml = sel_rmin.toxml(action="new")
-                node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
-
-                if sel_rmin.label: node_begin += sel_rmin.label + "'"
-                else: node_begin += "Unnamed token'"
-
-                node_begin += ">"
-                gametree = component.get('tree')
-                node_xml = node_begin + min_xml + '</nodehandler>'
-                print "Sending this XML to insert_xml:" + node_xml
-                gametree.insert_xml(node_xml)
-             #############
-        self.listctrl.DeleteAllItems()
-        self.refresh()
-        event.Skip()
-
-    def OnRightDown(self,event):
-        self.x = event.GetX()
-        self.y = event.GetY()
-        event.Skip()
-
-    def on_ok(self,evt):
-        self.EndModal(wx.ID_OK)
-
-class min_list_edit_dialog(wx.Dialog):
-    def __init__(self,parent,min_index, min_list, layers):
-        wx.Dialog.__init__(self,parent,-1,"token List",wx.DefaultPosition,wx.Size(600,530))
-        self.layers = layers
-        grid = layers['grid']
-        min = layers['tokens']
-        self.min_list = min_list
-        self.min_index = min_index
-        self.min = min
-        sizer1 = wx.BoxSizer(wx.VERTICAL)
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.grid = grid
-        editor = min_list_edit_panel(self, min_index, min_list,layers)
-        sizer1.Add(editor, 1, wx.EXPAND)
-        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        sizer1.Add(sizer, 0, wx.EXPAND)
-        self.editor = editor
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-        self.SetSizer(sizer1)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-    def on_revert(self,evt):
-        pass
-
-    def on_ok(self,evt):
-        self.editor.on_ok(self.layers)
-        self.EndModal(wx.ID_OK)
-
-class min_list_edit_panel(wx.Panel):
-    def __init__(self, parent, min_index, min_list,layers):
-        LABEL_COMBO = wx.NewId()
-        PATH_COMBO = wx.NewId()
-        POS_COMB = wx.NewId()
-        MIN_POS = wx.NewId()
-        POS_SPIN = wx.NewId()
-        self.grid = layers['grid']
-        self.min = layers['tokens'].tokens
-        self.min_list = min_list
-        self.min_index = min_index
-        self.layers = layers
-        wx.Panel.__init__(self, parent, -1)
-        self.min=min
-        listsizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"Token list properties"), wx.VERTICAL)
-        labelsizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.labelcheck = wx.CheckBox(self,-1,"Serialize")
-        labelsizer.Add(wx.StaticText(self, -1, "Label:          "), 0, wx.EXPAND)
-        labelsizer.Add(self.labelcheck,wx.ALIGN_RIGHT,wx.EXPAND)
-        listsizer.Add(labelsizer,0, wx.EXPAND)
-        self.labelcombo = wx.ComboBox(self, LABEL_COMBO,"no change",style=wx.CB_DROPDOWN)
-        listsizer.Add(self.labelcombo,0, wx.EXPAND)
-        self.pathcombo = wx.ComboBox(self, PATH_COMBO, "no change",style=wx.CB_DROPDOWN)
-        self.positioncombo = wx.ComboBox(self, POS_COMB, "no change", choices=["no change"], style=wx.CB_READONLY)
-        #self.positioncombo.SetValue(`min_list[0].pos`)
-        self.labelcombo.Append("no change")
-        self.pathcombo.Append("no change")
-        for m in min_list:
-            self.labelcombo.Append(min_list[min_list.index(m)].label)
-            self.pathcombo.Append(min_list[min_list.index(m)].path)
-            self.positioncombo.Append(`min_list[min_list.index(m)].pos`)
-        listsizer.Add(wx.StaticText(self, -1, "Path:"), 0, wx.EXPAND)
-        listsizer.Add(self.pathcombo, 0, wx.EXPAND)
-        listsizer.Add(wx.Size(10,10))
-        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
-            choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
-        self.heading.SetSelection( 9 )
-        listsizer.Add( self.heading, 0, wx.EXPAND )
-        listsizer.Add(wx.Size(10,10))
-
-        ## Remove
-        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
-        #    choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
-        #self.face.SetSelection(9)
-        #listsizer.Add(self.face, 0, wx.EXPAND)
-
-        ###
-        ###Group together locked, Hide, and snap radioboxes in group2 box
-        ###
-        group2 = wx.BoxSizer(wx.HORIZONTAL)
-        self.locked = wx.RadioBox(self, MIN_LOCK, "Lock", 
-            choices=["Don't lock","Lock","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.locked.SetSelection(2)
-        self.hide = wx.RadioBox(self, MIN_HIDE, "Hide", 
-            choices=["Don't hide", "Hide", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.hide.SetSelection(2)
-        self.snap = wx.RadioBox(self,MIN_ALIGN,"Snap",
-            choices=["Center","Top left","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.snap.SetSelection(2)
-        group2.Add(self.locked, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        group2.Add(self.hide, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        group2.Add(self.snap, 0, wx.EXPAND)
-        group2.Add(wx.Size(10,0))
-        listsizer.Add(group2,0,0)
-        ###
-        ###Group together the postion radiobox and the and its selection elements
-        ###
-        xpos = int(min_list[0].pos[0])
-        #xpos = int(`min_list[0].pos`[1:`min_list[0].pos`.index(',')])
-        ypos = int(min_list[0].pos[1])
-        #ypos = int(`min_list[0].pos`[`min_list[0].pos`.rfind(',')+1:len(`min_list[0].pos`)-1])
-        self.scx = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
-        self.scx.SetRange(0,self.grid.return_grid()[0])
-        self.scx.SetValue(xpos)
-        self.scy = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
-        self.scy.SetRange(0,self.grid.return_grid()[1])
-        self.scy.SetValue(1)
-        self.scy.SetValue(ypos)
-        positionbox = wx.BoxSizer(wx.HORIZONTAL)
-        self.poschoice = wx.RadioBox(self,MIN_POS,"Position",
-            choices=["Manual", "Existing", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
-        self.poschoice.SetSelection(2)
-        positionbox.Add(self.poschoice,0,0)
-        ###
-        ### group together choices under position choice boxsizer
-        ###
-        poschoicebox = wx.BoxSizer(wx.VERTICAL)
-            ###
-            ### spinbox contains the x and y spinctrls
-            ###
-        spinbox = wx.BoxSizer(wx.HORIZONTAL)
-        group2.Add(positionbox,0, wx.EXPAND)
-        xpos = wx.StaticText(self, -1,"XPOS:  ")
-        spinbox.Add(xpos,0, 0)
-        spinbox.Add(self.scx, 0, 0)
-        ypos = wx.StaticText(self, -1,"YPOS:  ")
-        spinbox.Add(ypos,0, 0)
-        spinbox.Add(self.scy, 0, 0)
-        poschoicebox.Add(wx.Size(0,15))
-        poschoicebox.Add(spinbox,0,0)
-        ###
-        ### kludge is just a way to horizontaly position text.  .Add doesn't seem to work.
-        ###
-        kluge = wx.BoxSizer(wx.HORIZONTAL)
-        klugetext = wx.StaticText(self, -1, "            ")
-        kluge.Add(klugetext,0,0)
-        kluge.Add(self.positioncombo,0,0)
-        poschoicebox.Add(wx.Size(0,1))
-        poschoicebox.Add(kluge,0,0)
-        positionbox.Add(poschoicebox,0,0)
-        listsizer.Add(positionbox,0, 0)
-        self.listsizer = listsizer
-        #self.outline = wx.StaticBox(self,-1,"token list properties")
-        #listsizer.Add(self.outline,0, wx.EXPAND)
-        self.SetSizer(listsizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-        self.Bind(wx.EVT_SPINCTRL, self.on_spin, id=POS_SPIN)
-        self.Bind(wx.EVT_TEXT, self.on_combo_box, id=POS_COMB)
-        #self.Bind(wx.EVT_SIZE, self.on_size)
-        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
-
-    def on_ok(self,min):
-        self.min = min
-        for m in self.min_list:
-            if self.hide.GetSelection() !=2: m.hide = self.hide.GetSelection()
-            if self.heading.GetSelection() !=9: m.heading = self.heading.GetSelection()
-            #if self.face.GetSelection() !=9: m.face = self.face.GetSelection()
-            if self.locked.GetSelection() !=2: m.locked = self.locked.GetSelection()
-            if self.snap.GetSelection() !=2: m.snap_to_align = self.snap.GetSelection()
-            if self.labelcombo.GetValue() != "no change":
-                m.label = self.labelcombo.GetValue()
-                if self.labelcheck.GetValue(): m.label += " " + `self.layers['tokens'].next_serial()`
-            if self.pathcombo.GetValue() != "no change":
-                path = self.pathcombo.GetValue()
-                image = self.evaluate(path)
-                if str(image[1]) != '-1':
-                    m.path = image[0]
-                    m.bmp = image[1]
-                else:
-                    image[-1] = -1
-                    while image[1] == -1:
-                        image = 0
-                        self.dlg = wx.TextEntryDialog(self, 
-                            'You entered an invalid URL for the image path.  Please Enter a valid URL or cancel to leave the old url unchanged')
-                        if self.dlg.ShowModal() == wx.ID_OK:
-                            path = self.dlg.GetValue()
-                            image = self.evaluate(path)
-                            if image[1] != -1:
-                                m.path = image[0]
-                                m.bmp = image[1]
-                            self.dlg.Destroy()
-                        else: break
-            if self.poschoice.GetSelection() !=2:
-                if self.poschoice.GetSelection() == 0: m.pos = cmpPoint(self.scx.GetValue(),self.scy.GetValue())
-                else:
-                    pos = self.positioncombo.GetValue()
-                    m.pos = cmpPoint(int(`pos`[2:`pos`.index(",")]),int(`pos`[`pos`.rfind(',')+1:len(`pos`)-2]))
-        self.layers["tokens"].canvas.send_map_data()
-
-    def evaluate(self, ckpath):
-        path = []
-        if ckpath[:7] != "http://": ckpath = "http://" + ckpath
-        path = self.check_path(ckpath)
-        return [ckpath, path]
-
-    def check_path(self, path):
-        if ImageHandler.Cache.has_key(path): return ImageHandler.Cache[path]
-        img = ImageHandler.directLoad(path)
-        if img is None: return -1
-        return img
-
-    def on_text(self,evt):
-        id=evt.GetId()
-
-    def on_spin(self,evt):
-        self.poschoice.SetSelection(0)
-
-    def on_combo_box(self,evt):
-        self.poschoice.SetSelection(1)
-
-    def on_radio_box(self,evt):
-        id=evt.GetId()
-        index = evt.GetInt()
-
-    def on_size(self,evt):
-        s = self.GetClientSizeTuple()
-        self.listsizer.SetDimension(20,20,s[0]-40,s[1]-40)
-        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
-
-##-----------------------------
-## token Prop Panel
-##-----------------------------
-
-MIN_LABEL = wx.NewId()
-MIN_HEADING = wx.NewId()
-MIN_FACE = wx.NewId()
-MIN_HIDE = wx.NewId()
-MIN_LOCK = wx.NewId()
-MIN_ALIGN = wx.NewId()
-wxID_MIN_WIDTH = wx.NewId()
-wxID_MIN_HEIGHT = wx.NewId()
-wxID_MIN_SCALING = wx.NewId()
-
-class min_edit_panel(wx.Panel):
-    def __init__(self, parent, min):
-        wx.Panel.__init__(self, parent, -1)
-        self.min = min
-        sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"token"), wx.VERTICAL)
-        sizerSize = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.label = wx.TextCtrl(self, MIN_LABEL, min.label)
-        sizer.Add(wx.StaticText(self, -1, "Label:"), 0, wx.EXPAND)
-        sizer.Add(self.label, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
-            choices=["None","N","NE",
-                     "E","SE","S",
-                     "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
-        self.heading.SetSelection(min.heading)
-        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
-        #    choices=["None","N","NE",
-        #             "E","SE","S",
-        #             "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
-        #self.face.SetSelection(min.face)
-        self.locked = wx.CheckBox(self, MIN_LOCK, " Lock")
-        self.locked.SetValue(min.locked)
-        self.hide = wx.CheckBox(self, MIN_HIDE, " Hide")
-        self.hide.SetValue(min.hide)
-        sizer.Add(self.heading, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        #sizer.Add(self.face, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        #
-        #image resizing
-        #
-        self.min_width_old_value = str(self.min.bmp.GetWidth())
-        self.min_width = wx.TextCtrl(self, wxID_MIN_WIDTH, self.min_width_old_value)
-        sizerSize.Add(wx.StaticText(self, -1, "Width: "), 0, wx.ALIGN_CENTER)
-        sizerSize.Add(self.min_width, 1, wx.EXPAND)
-        sizerSize.Add(wx.Size(20, 25))
-
-        #TODO:keep in mind that self.min is a local copy???
-        self.min_height_old_value = str(self.min.bmp.GetHeight())
-        self.min_height = wx.TextCtrl(self, wxID_MIN_HEIGHT, self.min_height_old_value)
-        sizerSize.Add(wx.StaticText(self, -1, "Height: "),0,wx.ALIGN_CENTER)
-        sizerSize.Add(self.min_height, 1, wx.EXPAND)
-        self.min_scaling = wx.CheckBox(self, wxID_MIN_SCALING, "Lock scaling")
-        self.min_scaling.SetValue(True)
-        sizerSize.Add(self.min_scaling, 1, wx.EXPAND)
-        sizer.Add(sizerSize, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10, 10))
-
-        # Now, add the last items on in their own sizer
-        hSizer.Add(self.locked, 0, wx.EXPAND)
-        hSizer.Add(wx.Size(10,10))
-        hSizer.Add(self.hide, 0, wx.EXPAND)
-
-        # Add the hSizer to the main sizer
-        sizer.Add( hSizer )
-        self.sizer = sizer
-        self.SetSizer(self.sizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-
-        #self.Bind(wx.EVT_SIZE, self.on_size)
-        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
-        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_WIDTH)
-        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_HEIGHT)
-        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
-        #self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
-
-    def on_scaling(self, evt):
-        if self.min_scaling.GetValue() == False: return
-        elif self.min_width.GetValue() and wxID_MIN_WIDTH == evt.GetId() and self.min_width.GetInsertionPoint():
-            self.min_height.SetValue(str(int((float(self.min_width.GetValue()) / float(self.min_width_old_value)) * float(self.min_height_old_value))) )
-        elif self.min_height.GetValue() and wxID_MIN_HEIGHT == evt.GetId() and self.min_height.GetInsertionPoint():
-            self.min_width.SetValue(str(int((float(self.min_height.GetValue()) / float(self.min_height_old_value)) * float(self.min_width_old_value))) )
-
-    def update_min(self):
-        self.min.set_min_props(self.heading.GetSelection(),
-                               #self.face.GetSelection(),
-                               self.label.GetValue(),
-                               self.locked.GetValue(),
-                               self.hide.GetValue(),
-                               self.min_width.GetValue(),
-                               self.min_height.GetValue())
-
-    def on_radio_box(self,evt):
-        id = evt.GetId()
-        index = evt.GetInt()
-
-    def on_text(self,evt):
-        id = evt.GetId()
-
-    def on_size(self,evt):
-        s = self.GetClientSizeTuple()
-        self.sizer.SetDimension(20,20,s[0]-40,s[1]-40)
-        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
-
-class min_edit_dialog(wx.Dialog):
-    def __init__(self,parent,min):
-        #520,265
-        wx.Dialog.__init__(self,parent,-1,"token",wx.DefaultPosition,wx.Size(520,350))
-        (w,h) = self.GetClientSizeTuple()
-        mastersizer = wx.BoxSizer(wx.VERTICAL)
-        editor = min_edit_panel(self,min)
-        #editor.SetDimensions(0,0,w,h-25)
-        self.editor = editor
-        mastersizer.Add(editor, 1, wx.EXPAND)
-        mastersizer.Add(wx.Size(10,10))
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
-        #sizer.SetDimension(0,h-25,w,25)
-        mastersizer.Add(sizer, 0, wx.EXPAND)
-        self.SetSizer(mastersizer)
-        self.SetAutoLayout(True)
-        self.Fit()
-        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
-
-    def on_ok(self,evt):
-        self.editor.update_min()
-        self.EndModal(wx.ID_OK)
--- a/plugins/bcg/token_handler.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,883 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/whiteboard_hander.py
-# Author: OpenRPG Team
-# Maintainer:
-# Version:
-#   $Id: token_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $
-#
-# Description: Token layer handler; derived from token Layer handler
-#
-__version__ = "$Id: token_handler.py,v 1.43 2007/12/07 20:39:50 madmathlabs Exp $"
-
-from orpg.mapper.base_handler import *
-from tok_dialogs import *
-import thread
-import time
-import mimetypes
-import urllib
-import xml.dom.minidom as minidom
-import wx
-
-## rewrite Grid
-from orpg.mapper.grid import GRID_RECTANGLE
-from orpg.mapper.grid import GRID_HEXAGON
-from orpg.mapper.grid import GRID_ISOMETRIC
-import os
-
-from orpg.tools.orpg_settings import settings
-
-## Jesus H! No Face, rotate!
-TOK_ROT_LEFT = wx.NewId()
-ROT_LEFT_45 = wx.NewId()
-LABEL_TOOL = wx.NewId()
-LAYER_TOOL = wx.NewId()
-TOK_LIST_TOOL = wx.NewId()
-TOK_TOOL = wx.NewId()
-TOK_URL = wx.NewId()
-SERIAL_TOOL = wx.NewId()
-TOK_MOVE = wx.NewId()
-TOK_REMOVE = wx.NewId()
-TOK_PROP_DLG = wx.NewId()
-TOK_FACING_NONE = wx.NewId()
-TOK_FACING_MATCH = wx.NewId()
-TOK_FACING_EAST = wx.NewId()
-TOK_FACING_WEST = wx.NewId()
-TOK_FACING_NORTH = wx.NewId()
-TOK_FACING_SOUTH = wx.NewId()
-TOK_FACING_NORTHEAST = wx.NewId()
-TOK_FACING_SOUTHEAST = wx.NewId()
-TOK_FACING_SOUTHWEST = wx.NewId()
-TOK_FACING_NORTHWEST = wx.NewId()
-TOK_HEADING_NONE = wx.NewId()
-TOK_HEADING_MATCH = wx.NewId()
-TOK_HEADING_EAST = wx.NewId()
-TOK_HEADING_WEST = wx.NewId()
-TOK_HEADING_NORTH = wx.NewId()
-TOK_HEADING_SOUTH = wx.NewId()
-TOK_HEADING_NORTHEAST = wx.NewId()
-TOK_HEADING_SOUTHEAST = wx.NewId()
-TOK_HEADING_SOUTHWEST = wx.NewId()
-TOK_HEADING_NORTHWEST = wx.NewId()
-TOK_HEADING_SUBMENU = wx.NewId()
-TOK_FACING_SUBMENU = wx.NewId()
-TOK_ALIGN_SUBMENU = wx.NewId()
-TOK_ALIGN_GRID_CENTER = wx.NewId()
-TOK_ALIGN_GRID_TL = wx.NewId()
-TOK_TITLE_HACK = wx.NewId()
-TOK_TO_GAMETREE = wx.NewId()
-TOK_BACK_ONE = wx.NewId()
-TOK_FORWARD_ONE = wx.NewId()
-TOK_TO_BACK = wx.NewId()
-TOK_TO_FRONT = wx.NewId()
-TOK_LOCK_BACK = wx.NewId()
-TOK_LOCK_FRONT = wx.NewId()
-TOK_FRONTBACK_UNLOCK = wx.NewId()
-TOK_ZORDER_SUBMENU = wx.NewId()
-TOK_SHOW_HIDE = wx.NewId()
-TOK_LOCK_UNLOCK = wx.NewId()
-MAP_REFRESH_MINI_URLS = wx.NewId()
-
-class myFileDropTarget(wx.FileDropTarget):
-    def __init__(self, handler):
-        wx.FileDropTarget.__init__(self)
-        self.m_handler = handler
-    def OnDropFiles(self, x, y, filenames):
-        self.m_handler.on_drop_files(x, y, filenames)
-
-class token_handler(base_layer_handler):
-
-    def __init__(self, parent, id, canvas):
-        self.sel_min = None
-        self.auto_label = 1
-        self.use_serial = 1
-        self.auto_label_cb = None
-        self.canvas = canvas
-        self.settings = settings
-        self.mini_rclick_menu_extra_items = {}
-        self.background_rclick_menu_extra_items = {}
-        base_layer_handler.__init__(self, parent, id, canvas)
-        # id is the index of the last good menu choice or 'None'
-        # if the last menu was left without making a choice
-        # should be -1 at other times to prevent events overlapping
-        self.lastMenuChoice = None
-        self.drag_mini = None
-        self.tooltip_delay_miliseconds = 500
-        self.tooltip_timer = wx.CallLater(self.tooltip_delay_miliseconds, self.on_tooltip_timer)
-        self.tooltip_timer.Stop()
-        dt = myFileDropTarget(self)
-        self.canvas.SetDropTarget(dt)
-        #wxInitAllImageHandlers()
-
-    def build_ctrls(self):
-        base_layer_handler.build_ctrls(self)
-        # add controls in reverse order! (unless you want them after the default tools)
-        self.auto_label_cb = wx.CheckBox(self, wx.ID_ANY, ' Auto Label ', (-1,-1),(-1,-1))
-        self.auto_label_cb.SetValue(self.auto_label)
-        self.min_url = wx.ComboBox(self, wx.ID_ANY, "http://", style=wx.CB_DROPDOWN | wx.CB_SORT)
-        self.localBrowse = wx.Button(self, wx.ID_ANY, 'Browse', style=wx.BU_EXACTFIT)
-        minilist = createMaskedButton( self, dir_struct["icon"]+'questionhead.gif', 'Edit token properties', wx.ID_ANY)
-        miniadd = wx.Button(self, wx.ID_OK, "Add Token", style=wx.BU_EXACTFIT)
-        self.sizer.Add(self.auto_label_cb,0,wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(self.min_url, 1, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(miniadd, 0, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(self.localBrowse, 0, wx.ALIGN_CENTER)
-        self.sizer.Add((6, 0))
-        self.sizer.Add(minilist, 0, wx.ALIGN_CENTER)
-        self.Bind(wx.EVT_BUTTON, self.on_min_list, minilist)
-        self.Bind(wx.EVT_BUTTON, self.on_token, miniadd)
-        self.Bind(wx.EVT_BUTTON, self.on_browse, self.localBrowse)
-        self.Bind(wx.EVT_CHECKBOX, self.on_label, self.auto_label_cb)
-
-    def on_browse(self, evt):
-        if not self.role_is_gm_or_player(): return
-        dlg = wx.FileDialog(None, "Select a Token to load", dir_struct["user"]+'webfiles/', 
-            wildcard="Image files (*.bmp, *.gif, *.jpg, *.png)|*.bmp;*.gif;*.jpg;*.png", style=wx.OPEN)
-        if not dlg.ShowModal() == wx.ID_OK:
-            dlg.Destroy()
-            return
-        file = open(dlg.GetPath(), "rb")
-        imgdata = file.read()
-        file.close()
-        filename = dlg.GetFilename()
-        (imgtype,j) = mimetypes.guess_type(filename)
-        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
-
-        ## Removal of Remote Server?
-        if self.settings.get_setting('LocalorRemote') == 'Remote':
-            # make the new mini appear in top left of current viewable map
-            dc = wx.ClientDC(self.canvas)
-            self.canvas.PrepareDC(dc)
-            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-            x = dc.DeviceToLogicalX(0)
-            y = dc.DeviceToLogicalY(0)
-            thread.start_new_thread(self.canvas.layers['token'].upload, 
-                                    (postdata, dlg.GetPath()), {'pos':cmpPoint(x,y)})
-        else:
-            try: min_url = component.get("cherrypy") + filename
-            except: return #chat.InfoPost('CherryPy is not started!')
-            min_url = dlg.GetDirectory().replace(dir_struct["user"]+'webfiles' + os.sep, 
-                component.get("cherrypy")) + '/' + filename
-            # build url
-            if min_url == "" or min_url == "http://": return
-            if min_url[:7] != "http://": min_url = "http://" + min_url
-            # make label
-            if self.auto_label and min_url[-4:-3] == '.':
-                start = min_url.rfind("/") + 1
-                min_label = min_url[start:len(min_url)-4]
-                if self.use_serial: min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
-            else: min_label = ""
-            if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
-            try:
-                id = 'mini-' + self.canvas.frame.session.get_next_id()
-                # make the new mini appear in top left of current viewable map
-                dc = wx.ClientDC(self.canvas)
-                self.canvas.PrepareDC(dc)
-                dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-                x = dc.DeviceToLogicalX(0)
-                y = dc.DeviceToLogicalY(0)
-                self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
-            except:
-                # When there is an exception here, we should be decrementing the serial_number for reuse!!
-                unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
-                dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
-                dlg.ShowModal()
-                dlg.Destroy()
-                self.canvas.layers['token'].rollback_serial()
-            self.canvas.send_map_data()
-            self.canvas.Refresh(False)
-
-
-    def build_menu(self,label = "Token"):
-        ## Menu Changes: Rotate
-        ## Menu into Component
-        ## Remove To GameTree option
-        base_layer_handler.build_menu(self,label)
-        self.main_menu.AppendSeparator()
-        self.main_menu.Append(LABEL_TOOL,"&Auto label","",1)
-        self.main_menu.Check(LABEL_TOOL,self.auto_label)
-        self.main_menu.Append(SERIAL_TOOL,"&Number minis","",1)
-        self.main_menu.Check(SERIAL_TOOL, self.use_serial)
-        self.main_menu.Append(MAP_REFRESH_MINI_URLS,"&Refresh tokens")       #  Add the menu item
-        self.main_menu.AppendSeparator()
-        self.main_menu.Append(TOK_MOVE, "Move")
-        self.canvas.Bind(wx.EVT_MENU, self.on_map_board_menu_item, id=MAP_REFRESH_MINI_URLS) #  Set the handler
-        self.canvas.Bind(wx.EVT_MENU, self.on_label, id=LABEL_TOOL)
-        self.canvas.Bind(wx.EVT_MENU, self.on_serial, id=SERIAL_TOOL)
-        # build token menu
-        self.min_menu = wx.Menu()
-        # Rectangles and hexagons require slightly different menus because of
-        # facing and heading possibilities.
-
-        rot_left = wx.Menu()
-        rot_left_45 = rot_left.Append(-1, '45*')
-        self.canvas.Bind(wx.EVT_MENU, self.rot_left_45, rot_left_45)
-        rot_right = wx.Menu()
-
-        rot_right_45 = rot_right.Append(-1, '45*')
-        self.canvas.Bind(wx.EVT_MENU, self.rot_right_45, rot_right_45)
-        ## Replace with Rotate. Left - Right, 45 - 90 degress.
-        """
-        face_menu = wx.Menu()
-        face_menu.Append(TOK_FACING_NONE,"&None")
-        face_menu.Append(TOK_FACING_NORTH,"&North")
-        face_menu.Append(TOK_FACING_NORTHEAST,"Northeast")
-        face_menu.Append(TOK_FACING_EAST,"East")
-        face_menu.Append(TOK_FACING_SOUTHEAST,"Southeast")
-        face_menu.Append(TOK_FACING_SOUTH,"&South")
-        face_menu.Append(TOK_FACING_SOUTHWEST,"Southwest")
-        face_menu.Append(TOK_FACING_WEST,"West")
-        face_menu.Append(TOK_FACING_NORTHWEST,"Northwest")
-        """
-        ###
-
-        heading_menu = wx.Menu()
-        heading_menu.Append(TOK_HEADING_NONE,"&None")
-        heading_menu.Append(TOK_HEADING_NORTH,"&North")
-        heading_menu.Append(TOK_HEADING_NORTHEAST,"Northeast")
-        heading_menu.Append(TOK_HEADING_EAST,"East")
-        heading_menu.Append(TOK_HEADING_SOUTHEAST,"Southeast")
-        heading_menu.Append(TOK_HEADING_SOUTH,"&South")
-        heading_menu.Append(TOK_HEADING_SOUTHWEST,"Southwest")
-        heading_menu.Append(TOK_HEADING_WEST,"West")
-        heading_menu.Append(TOK_HEADING_NORTHWEST,"Northwest")
-
-        align_menu = wx.Menu()
-        align_menu.Append(TOK_ALIGN_GRID_CENTER,"&Center")
-        align_menu.Append(TOK_ALIGN_GRID_TL,"&Top-Left")
-        #  This is a hack to simulate a menu title, due to problem in Linux
-        if wx.Platform == '__WXMSW__': self.min_menu.SetTitle(label)
-        else:
-            self.min_menu.Append(TOK_TITLE_HACK,label)
-            self.min_menu.AppendSeparator()
-        self.min_menu.Append(TOK_SHOW_HIDE,"Show / Hide")
-        self.min_menu.Append(TOK_LOCK_UNLOCK, "Lock / Unlock")
-        self.min_menu.Append(TOK_REMOVE,"&Remove")
-
-        ##Remove
-        #self.min_menu.Append(TOK_TO_GAMETREE,"To &Gametree")
-        ###
-
-        self.min_menu.AppendMenu(TOK_HEADING_SUBMENU,"Set &Heading",heading_menu)
-
-        ##Remove
-        self.min_menu.AppendMenu(TOK_ROT_LEFT,"&Rotate Left",rot_left)
-        self.min_menu.AppendMenu(wx.ID_ANY,"&Rotate Right",rot_right)
-        ###
-
-        self.min_menu.AppendMenu(TOK_ALIGN_SUBMENU,"Snap-to &Alignment",align_menu)
-        self.min_menu.AppendSeparator()
-        zorder_menu = wx.Menu()
-        zorder_menu.Append(TOK_BACK_ONE,"Back one")
-        zorder_menu.Append(TOK_FORWARD_ONE,"Forward one")
-        zorder_menu.Append(TOK_TO_BACK,"To back")
-        zorder_menu.Append(TOK_TO_FRONT,"To front")
-        zorder_menu.AppendSeparator()
-        zorder_menu.Append(TOK_LOCK_BACK,"Lock to back")
-        zorder_menu.Append(TOK_LOCK_FRONT,"Lock to front")
-        zorder_menu.Append(TOK_FRONTBACK_UNLOCK,"Unlock Front/Back")
-        self.min_menu.AppendMenu(TOK_ZORDER_SUBMENU, "Token Z-Order",zorder_menu)
-        #self.min_menu.Append(TOK_LOCK,"&Lock")
-        self.min_menu.AppendSeparator()
-        self.min_menu.Append(TOK_PROP_DLG,"&Properties")
-
-
-        #self.min_menu.AppendSeparator()
-        #self.min_menu.Append(TOK_MOVE, "Move")
-
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_MOVE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_SHOW_HIDE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_UNLOCK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_REMOVE)
-
-        ##Remove
-        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_GAMETREE)
-        ###
-
-        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_PROP_DLG)
-
-        ##Remove
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_EAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_WEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHWEST)
-        ###
-
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_EAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_WEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTH)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHEAST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHWEST)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_CENTER)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_TL)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_BACK_ONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FORWARD_ONE)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_BACK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_FRONT)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_BACK)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_FRONT)
-        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FRONTBACK_UNLOCK)
-        ######### add plugin added menu items #########
-        if len(self.mini_rclick_menu_extra_items)>0:
-            self.min_menu.AppendSeparator()
-            for item in self.mini_rclick_menu_extra_items.items(): self.min_menu.Append(item[1], item[0])
-        if len(self.background_rclick_menu_extra_items)>0:
-            self.main_menu.AppendSeparator()
-            for item in self.background_rclick_menu_extra_items.items():
-                self.main_menu.Append(item[1], item[0])
-
-    def do_min_menu(self,pos):
-        self.canvas.PopupMenu(self.min_menu,pos)
-
-    def rot_left_45(self, evt):
-        #self.sel_rmin.rotate += 0.785
-        self.sel_rmin.rotate += 1.046
-        #component.get('drawn')[self.sel_rmin] = False
-
-    def rot_right_45(self, evt):
-        #self.sel_rmin.rotate -= 0.785
-        self.sel_rmin.rotate -= 1.046
-
-    def do_min_select_menu(self, min_list, pos):
-        # to prevent another event being processed
-        self.lastMenuChoice = None
-        self.min_select_menu = wx.Menu()
-        self.min_select_menu.SetTitle("Select Token")
-        loop_count = 1
-        try:
-            for m in min_list:
-                # Either use the token label for the selection list
-                if m.label: self.min_select_menu.Append(loop_count, m.label)
-                # Or use part of the images filename as an identifier
-                else:
-                    string_split = string.split(m.path,"/",)
-                    last_string = string_split[len(string_split)-1]
-                    self.min_select_menu.Append(loop_count, 'Unlabeled - ' + last_string[:len(last_string)-4])
-                self.canvas.Bind(wx.EVT_MENU, self.min_selected, id=loop_count)
-                loop_count += 1
-            self.canvas.PopupMenu(self.min_select_menu,pos)
-        except: pass
-
-    def min_selected(self,evt):
-        # this is the callback function for the menu that is used to choose
-        # between minis when you right click, left click or left double click
-        # on a stack of two or more
-        self.canvas.Refresh(False)
-        self.canvas.send_map_data()
-        self.lastMenuChoice = evt.GetId()-1
-
-    def on_min_menu_item(self,evt):
-        id = evt.GetId()
-        if id == TOK_MOVE:
-            if self.sel_min:
-                self.moveSelectedMini(self.last_rclick_pos)
-                self.deselectAndRefresh()
-            return
-        elif id == TOK_REMOVE: self.canvas.layers['token'].del_token(self.sel_rmin)
-
-        ##Remove
-        elif id == TOK_TO_GAMETREE:
-            min_xml = self.sel_rmin.toxml(action="new")
-            node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
-            if self.sel_rmin.label: node_begin += self.sel_rmin.label + "'"
-            else:  node_begin += "Unnamed token'"
-            node_begin += ">"
-	    gametree = component.get('tree')
-            node_xml = node_begin + min_xml + '</nodehandler>'
-            #print "Sending this XML to insert_xml:" + node_xml
-            gametree.insert_xml(str(node_xml))
-
-        elif id == TOK_SHOW_HIDE:
-            if self.sel_rmin.hide:  self.sel_rmin.hide = 0
-            else: self.sel_rmin.hide = 1
-        elif id == TOK_LOCK_UNLOCK:
-            if self.sel_rmin.locked: self.sel_rmin.locked = False
-            else: self.sel_rmin.locked = True
-            if self.sel_rmin == self.sel_min:
-                # when we lock / unlock the selected mini make sure it isn't still selected
-                # or it might easily get moved by accident and be hard to move back
-                self.sel_min.selected = False
-                self.sel_min.isUpdated = True
-                self.sel_min = None
-	recycle_bin = {TOK_HEADING_NONE: FACE_NONE, TOK_HEADING_NORTH: FACE_NORTH, 
-        TOK_HEADING_NORTHWEST: FACE_NORTHWEST, TOK_HEADING_NORTHEAST: FACE_NORTHEAST, 
-        TOK_HEADING_EAST: FACE_EAST, TOK_HEADING_SOUTHEAST: FACE_SOUTHEAST, TOK_HEADING_SOUTHWEST: FACE_SOUTHWEST, 
-        TOK_HEADING_SOUTH: FACE_SOUTH, TOK_HEADING_WEST: FACE_WEST}
-	if recycle_bin.has_key(id):
-	    self.sel_rmin.heading = recycle_bin[id]
-	    del recycle_bin
-	recycle_bin = {TOK_FACING_NONE: FACE_NONE, TOK_FACING_NORTH: FACE_NORTH, 
-        TOK_FACING_NORTHWEST: FACE_NORTHWEST, TOK_FACING_NORTHEAST: FACE_NORTHEAST, 
-        TOK_FACING_EAST: FACE_EAST, TOK_FACING_SOUTHEAST: FACE_SOUTHEAST, TOK_FACING_SOUTHWEST: FACE_SOUTHWEST, 
-        TOK_FACING_SOUTH: FACE_SOUTH, TOK_FACING_WEST: FACE_WEST}
-	if recycle_bin.has_key(id):
-	    self.sel_rmin.face = recycle_bin[id]
-	    del recycle_bin
-        elif id == TOK_ALIGN_GRID_CENTER: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_CENTER
-        elif id == TOK_ALIGN_GRID_TL: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_TL
-        elif id == TOK_PROP_DLG:
-            old_lock_value = self.sel_rmin.locked
-            dlg = min_edit_dialog(self.canvas.frame.GetParent(),self.sel_rmin)
-            if dlg.ShowModal() == wx.ID_OK:
-                if self.sel_rmin == self.sel_min and self.sel_rmin.locked != old_lock_value:
-                    # when we lock / unlock the selected mini make sure it isn't still selected
-                    # or it might easily get moved by accident and be hard to move back
-                    self.sel_min.selected = False
-                    self.sel_min.isUpdated = True
-                    self.sel_min = None
-                self.canvas.Refresh(False)
-                self.canvas.send_map_data()
-                return
-
-        elif id == TOK_BACK_ONE:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-		##   print "old z-order = " + str(oldz)
-                self.sel_rmin.zorder -= 1
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_FORWARD_ONE:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-	    ##  print "old z-order = " + str(oldz)
-            self.sel_rmin.zorder += 1
-
-            #  Re-collapse to normalize
-            #  Note:  only one update (with the final values) will be sent
-            self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_TO_FRONT:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-	    ##  print "old z-order = " + str(oldz)
-                #  The new z-order will be one more than the last index
-                newz = len(self.canvas.layers['token'].token)
-	    ##  print "new z-order = " + str(newz)
-                self.sel_rmin.zorder = newz
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_TO_BACK:
-            #  This assumes that we always start out with a z-order
-            #     that starts at 0 and goes up to the number of
-            #     minis - 1.  If this isn't the case, then execute
-            #     a self.canvas.layers['token'].collapse_zorder()
-            #     before getting the oldz to test
-            #  Save the selected minis current z-order
-            oldz = self.sel_rmin.zorder
-            # Make sure the mini isn't sticky front or back
-            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
-	    ##  print "old z-order = " + str(oldz)
-
-                #  Since 0 is the lowest in a normalized order, be one less
-                newz = -1
-	    ##  print "new z-order = " + str(newz)
-                self.sel_rmin.zorder = newz
-                #  Re-collapse to normalize
-                #  Note:  only one update (with the final values) will be sent
-                self.canvas.layers['token'].collapse_zorder()
-
-        elif id == TOK_FRONTBACK_UNLOCK:
-            #print "Unlocked/ unstickified..."
-            if self.sel_rmin.zorder == TOK_STICKY_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK + 1
-            elif self.sel_rmin.zorder == TOK_STICKY_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT - 1
-        elif id == TOK_LOCK_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK
-        elif id == TOK_LOCK_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT
-        # Pretty much, we always want to refresh when we go through here
-        # This helps us remove the redundant self.Refresh() on EVERY menu event
-        # that we process above.
-        self.sel_rmin.isUpdated = True
-        self.canvas.Refresh(False)
-        self.canvas.send_map_data()
-
-    def on_token(self, evt):
-        session = self.canvas.frame.session
-        if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER) and (session.use_roles()):
-            self.infoPost("You must be either a player or GM to use the token Layer")
-            return
-        min_url = self.min_url.GetValue()
-        # build url
-        if min_url == "" or min_url == "http://": return
-        if min_url[:7] != "http://" : min_url = "http://" + min_url
-        # make label
-        if self.auto_label and min_url[-4:-3] == '.':
-            start = min_url.rfind("/") + 1
-            min_label = min_url[start:len(min_url)-4]
-            if self.use_serial:
-                min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
-        else: min_label = ""
-        if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
-        try:
-            id = 'mini-' + self.canvas.frame.session.get_next_id()
-            # make the new mini appear in top left of current viewable map
-            dc = wx.ClientDC(self.canvas)
-            self.canvas.PrepareDC(dc)
-            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-            x = dc.DeviceToLogicalX(0)
-            y = dc.DeviceToLogicalY(0)
-            self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
-        except:
-            # When there is an exception here, we should be decrementing the serial_number for reuse!!
-            unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
-            #print unablemsg
-            dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
-            dlg.ShowModal()
-            dlg.Destroy()
-            self.canvas.layers['token'].rollback_serial()
-        self.canvas.send_map_data()
-        self.canvas.Refresh(False)
-        #except Exception, e:
-            #wx.MessageBox(str(e),"token Error")
-
-    def on_label(self,evt):
-        self.auto_label = not self.auto_label
-        self.auto_label_cb.SetValue(self.auto_label)
-        #self.send_map_data()
-        #self.Refresh()
-
-    def on_min_list(self,evt):
-        session = self.canvas.frame.session
-        if (session.my_role() != session.ROLE_GM):
-            self.infoPost("You must be a GM to use this feature")
-            return
-        #d = min_list_panel(self.frame.GetParent(),self.canvas.layers,"token list")
-        d = min_list_panel(self.canvas.frame,self.canvas.layers,"token list")
-        if d.ShowModal() == wx.ID_OK: d.Destroy()
-        self.canvas.Refresh(False)
-
-    def on_serial(self, evt):
-        self.use_serial = not self.use_serial
-
-    def on_map_board_menu_item(self,evt):
-        id = evt.GetId()
-        if id == MAP_REFRESH_MINI_URLS:   # Note: this doesn't change the mini, so no need to update the map
-            for mini in self.canvas.layers['token'].tokens:       #  For all minis
-                mini.set_bmp(ImageHandler.load(mini.path, 'token', mini.id))      #  Reload their bmp member
-            self.canvas.Refresh(False)
-
-####################################################################
-    ## old functions, changed an awful lot
-
-    def on_left_down(self, evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini:
-            deselecting_selected_mini = (mini == self.sel_min) #clicked on the selected mini
-            self.deselectAndRefresh()
-            self.drag_mini = mini
-            if deselecting_selected_mini: return
-            self.sel_min = mini
-            self.sel_min.selected = True
-            self.canvas.Refresh()
-        else:
-            self.drag_mini = None
-            pos = self.getLogicalPosition(evt)
-            self.moveSelectedMini(pos)
-            self.deselectAndRefresh()
-
-    def on_right_down(self, evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        self.last_rclick_pos = self.getLogicalPosition(evt)
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini:
-            self.sel_rmin = mini
-            if self.sel_min: self.min_menu.Enable(TOK_MOVE, True)
-            else: self.min_menu.Enable(TOK_MOVE, False)
-            self.prepare_mini_rclick_menu(evt)
-            self.do_min_menu(evt.GetPosition())
-        else:# pass it on
-            if self.sel_min: self.main_menu.Enable(TOK_MOVE, True)
-            else: self.main_menu.Enable(TOK_MOVE, False)
-            self.prepare_background_rclick_menu(evt)
-            base_layer_handler.on_right_down(self, evt)
-
-####################################################################
-    ## new functions
-
-    def on_drop_files(self, x, y, filepaths):
-        # currently we ignore multiple files
-        filepath = filepaths[0]
-        start1 = filepath.rfind("\\") + 1 # check for both slashes in path to be on the safe side
-        start2 = filepath.rfind("/") + 1
-        if start1 < start2: start1 = start2
-        filename = filepath[start1:]
-        pos = filename.rfind('.')
-        ext = filename[pos:].lower()
-        #ext = filename[-4:].lower()
-        if(ext != ".bmp" and ext != ".gif" and ext != ".jpg" and ext != ".jpeg" and ext != ".png"):
-            self.infoPost("Supported file extensions are: *.bmp, *.gif, *.jpg, *.jpeg, *.png")
-            return
-        file = open(filepath, "rb")
-        imgdata = file.read()
-        file.close()
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        x = dc.DeviceToLogicalX(x)
-        y = dc.DeviceToLogicalY(y)
-        (imgtype,j) = mimetypes.guess_type(filename)
-        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
-        thread.start_new_thread(self.canvas.layers['token'].upload, (postdata, filepath), {'pos':cmpPoint(x,y)})
-
-    def on_tooltip_timer(self, *args):
-        pos = args[0]
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        pos = wx.Point(dc.DeviceToLogicalX(pos.x), dc.DeviceToLogicalY(pos.y))
-        mini_list = self.getMiniListOrSelectedMini(pos)
-        if len(mini_list) > 0:
-            print mini_list
-            tooltip = self.get_mini_tooltip(mini_list); print tooltip
-            self.canvas.SetToolTipString(tooltip)
-        else: self.canvas.SetToolTipString("")
-
-    def on_motion(self,evt):
-        if evt.Dragging() and evt.LeftIsDown():
-            if self.canvas.drag is None and self.drag_mini is not None:
-                drag_bmp = self.drag_mini.bmp
-                if self.drag_mini.width and self.drag_mini.height:
-                    tmp_image = drag_bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.drag_mini.width * self.canvas.layers['grid'].mapscale), 
-                        int(self.drag_mini.height * self.canvas.layers['grid'].mapscale))
-                    tmp_image.ConvertAlphaToMask()
-
-                    ### Should show rotated image when dragging.
-                    if self.drag_mini.rotate != 0 :
-                        tmp_image = tmp_image.Rotate(self.drag_mini.rotate, 
-                                                    (self.drag_mini.width/2, self.drag_mini.height/2))
-
-                    drag_bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(drag_bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    drag_bmp.SetMask(mask)
-                    tmp_image = tmp_image.ConvertToGreyscale()
-                    self.drag_mini.gray = True
-                    self.drag_mini.isUpdated = True
-                    def refresh():
-                        self.canvas.drag.Hide()
-                        self.canvas.Refresh(False)
-                    wx.CallAfter(refresh)
-                self.canvas.drag = wx.DragImage(drag_bmp)
-                self.drag_offset = self.getLogicalPosition(evt)- self.drag_mini.pos
-                self.canvas.drag.BeginDrag((int(self.drag_offset.x * self.canvas.layers['grid'].mapscale), 
-                    int(self.drag_offset.y * self.canvas.layers['grid'].mapscale)), self.canvas, False)
-            elif self.canvas.drag is not None:
-                self.canvas.drag.Move(evt.GetPosition())
-                self.canvas.drag.Show()
-        # reset tool tip timer
-        self.canvas.SetToolTipString("")
-        self.tooltip_timer.Restart(self.tooltip_delay_miliseconds, evt.GetPosition())
-
-    def on_left_up(self,evt):
-        if self.canvas.drag:
-            self.canvas.drag.Hide()
-            self.canvas.drag.EndDrag()
-            self.canvas.drag = None
-            pos = self.getLogicalPosition(evt)
-            pos = pos - self.drag_offset
-            if self.canvas.layers['grid'].snap:
-                nudge = int(self.canvas.layers['grid'].unit_size/2)
-                if self.canvas.layers['grid'].mode != GRID_ISOMETRIC:
-                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
-                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2),int(self.drag_mini.bmp.GetHeight()/2))
-                    else: pos = pos + (nudge, nudge)
-                else:# GRID_ISOMETRIC
-                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
-                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2), self.drag_mini.bmp.GetHeight())
-                    else: pass # no nudge for the isomorphic / top-left
-            self.sel_min = self.drag_mini
-            # check to see if the mouse is inside the window still
-            w = self.canvas.GetClientSizeTuple() # this is the window size, minus any scrollbars
-            p = evt.GetPosition() # compare the window size, w with the non-logical position
-            c = self.canvas.size # this is the grid size, compare with the logical position, pos
-            # both are [width, height]
-            if p.x>=0 and pos.x<c[0] and p.x<w[0] and p.y>=0 and pos.y<c[1] and p.y<w[1]:
-                self.moveSelectedMini(pos)
-            self.sel_min.gray = False
-            self.sel_min.selected = False
-            self.sel_min.isUpdated = True
-            self.canvas.Refresh(False)
-            self.canvas.send_map_data()
-            self.sel_min = None
-        self.drag_mini = None
-
-    def on_left_dclick(self,evt):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
-        if mini: self.on_mini_dclick(evt, mini)
-        else: base_layer_handler.on_left_dclick(self, evt)
-
-
-####################################################################
-    ## hook functions (although with python you can override any of the functions)
-
-    def prepare_mini_rclick_menu(self, evt):
-        # override the entire right-click on a mini menu
-        pass
-
-    def prepare_background_rclick_menu(self, evt):
-        # override the entire right-click on the map menu
-        pass
-
-    def get_mini_tooltip(self, mini_list):
-        # override to create a tooltip
-        return ""
-
-    def on_mini_dclick(self, evt, mini):
-        # do something after the mini was left double clicked
-        pass
-
-####################################################################
-    ## easy way to add a single menu item
-
-    def set_mini_rclick_menu_item(self, label, callback_function):
-        # remember you might want to call these at the end of your callback function:
-        # mini_handler.sel_rmin.isUpdated = True
-        # canvas.Refresh(False)
-        # canvas.send_map_data()
-        if callback_function == None: del self.mini_rclick_menu_extra_items[label]
-        else:
-            if not self.mini_rclick_menu_extra_items.has_key(label):
-                self.mini_rclick_menu_extra_items[label]=wx.NewId()
-            menu_id = self.mini_rclick_menu_extra_items[label]
-            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
-        self.build_menu()
-
-    def set_background_rclick_menu_item(self, label, callback_function):
-        if callback_function == None: del self.background_rclick_menu_extra_items[label]
-        else:
-            if not self.background_rclick_menu_extra_items.has_key(label):
-                self.background_rclick_menu_extra_items[label]=wx.NewId()
-            menu_id = self.background_rclick_menu_extra_items[label]
-            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
-        self.build_menu()
-
-
-####################################################################
-    ## helper functions
-
-    def infoPost(self, message):
-        component.get("chat").InfoPost(message)
-
-    def role_is_gm_or_player(self):
-        session = self.canvas.frame.session
-        if (session.my_role() <> session.ROLE_GM) and (session.my_role() <> session.ROLE_PLAYER) and (session.use_roles()):
-            self.infoPost("You must be either a player or GM to use the token Layer")
-            return False
-        return True
-
-    def role_is_gm(self):
-        session = self.canvas.frame.session
-        if (session.my_role() <> session.ROLE_GM) and (session.use_roles()): return False
-        return True
-
-    def alreadyDealingWithMenu(self):
-        return self.lastMenuChoice is not None
-
-    def getLastMenuChoice(self):
-        choice = self.lastMenuChoice
-        self.lastMenuChoice = None
-        return choice
-
-    def getLogicalPosition(self, evt):
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
-        pos = evt.GetLogicalPosition(dc)
-        return pos
-
-    def getMiniListOrSelectedMini(self, pos, include_locked=False):
-        if self.sel_min and self.sel_min.hit_test(pos):
-            # clicked on the selected mini - assume that is the intended target
-            # and don't give a choice of it and any other minis stacked with it
-            mini_list = []
-            mini_list.append(self.sel_min)
-            return mini_list
-        mini_list = self.canvas.layers['token'].find_token(pos, (not include_locked))
-        if mini_list: return mini_list
-        mini_list = []
-        return mini_list
-
-    def deselectAndRefresh(self):
-        if self.sel_min:
-            self.sel_min.selected = False
-            self.sel_min.isUpdated = True
-            self.canvas.Refresh(False)
-            self.canvas.send_map_data()
-            self.sel_min = None
-
-    def moveSelectedMini(self, pos):
-        if self.sel_min: self.moveMini(pos, self.sel_min)
-
-    def moveMini(self, pos, mini):
-        grid = self.canvas.layers['grid']
-        mini.pos = grid.get_snapped_to_pos(pos, mini.snap_to_align, mini.bmp.GetWidth(), mini.bmp.GetHeight())
-
-    def find_mini(self, evt, include_locked):
-        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
-        pos = self.getLogicalPosition(evt)
-        mini_list = self.getMiniListOrSelectedMini(pos, include_locked)
-        mini = None
-        if len(mini_list) > 1:
-            try: self.do_min_select_menu(mini_list, evt.GetPosition())
-            except: pass
-            choice = self.getLastMenuChoice()
-            if choice == None: return None # left menu without making a choice, eg by clicking outside menu
-            mini = mini_list[choice]
-        elif len(mini_list) == 1: mini = mini_list[0]
-        return mini
-
--- a/plugins/bcg/tokens.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,600 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/tokens.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: tokens.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-#
-__version__ = "$Id: tokens.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
-
-from orpg.mapper.base import *
-import thread
-import time
-import urllib
-import os.path
-
-from orpg.tools.orpg_settings import settings
-
-MIN_STICKY_BACK = -0XFFFFFF
-MIN_STICKY_FRONT = 0xFFFFFF
-
-##----------------------------------------
-##  token object
-##----------------------------------------
-
-FACE_NONE = 0
-FACE_NORTH = 1
-FACE_NORTHEAST = 2
-FACE_EAST = 3
-FACE_SOUTHEAST = 4
-FACE_SOUTH = 5
-FACE_SOUTHWEST = 6
-FACE_WEST = 7
-FACE_NORTHWEST = 8
-SNAPTO_ALIGN_CENTER = 0
-SNAPTO_ALIGN_TL = 1
-
-def cmp_zorder(first,second):
-    f = first.zorder
-    s = second.zorder
-    if f == None: f = 0
-    if s == None: s = 0
-    if f == s: value = 0
-    elif f < s: value = -1
-    else: value = 1
-    return value
-
-class BmpToken:
-    def __init__(self, id,path, bmp, pos=cmpPoint(0,0), 
-                heading=FACE_NONE, rotate=0, label="", 
-                locked=False, hide=False, snap_to_align=SNAPTO_ALIGN_CENTER, 
-                zorder=0, width=0, height=0, log=None, local=False, localPath='', localTime=-1):
-        self.heading = heading
-        self.rotate = rotate
-        self.label = label
-        self.path = path
-        self.bmp = bmp
-        self.pos = pos
-        self.selected = False
-        self.locked = locked
-        self.snap_to_align = snap_to_align
-        self.hide = hide
-        self.id = id
-        self.zorder = zorder
-        self.left = 0
-        self.local = local
-        self.localPath = localPath
-        self.localTime = localTime
-        if not width: self.width = 0
-        else: self.width = width
-        if not height: self.height = 0
-        else: self.height = height
-        self.right = bmp.GetWidth()
-        self.top = 0
-        self.bottom = bmp.GetHeight()
-        self.isUpdated = False
-        self.gray = False
-        self.drawn = {}
-
-    def __del__(self):
-        del self.bmp
-        self.bmp = None
-
-    def set_bmp(self, bmp):
-        self.bmp = bmp
-
-    def set_min_props(self, heading=FACE_NONE, rotate=0, label="", locked=False, hide=False, width=0, height=0):
-        self.heading = heading
-        self.rotate = rotate
-        self.label = label
-        if locked: self.locked = True
-        else: self.locked = False
-        if hide: self.hide = True
-        else: self.hide = False
-        self.width = int(width)
-        self.height = int(height)
-        self.isUpdated = True
-
-    def hit_test(self, pt):
-        rect = self.get_rect()
-        result = None
-        result = rect.InsideXY(pt.x, pt.y)
-        return result
-
-    def get_rect(self):
-        ret = wx.Rect(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-        return ret
-
-    def draw(self, dc, mini_layer, op=wx.COPY):
-        if isinstance(self.bmp, tuple):
-            self.bmp = wx.ImageFromMime(self.bmp[1], self.bmp[2]).ConvertToBitmap()
-        if self.bmp != None and self.bmp.Ok():
-            # check if hidden and GM: we outline the mini in grey (little bit smaller than the actual size)
-            # and write the label in the center of the mini
-            if self.hide and mini_layer.canvas.frame.session.my_role() == mini_layer.canvas.frame.session.ROLE_GM:
-                # set the width and height of the image
-                if self.width and self.height:
-                    tmp_image = self.bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.width), int(self.height))
-                    tmp_image.ConvertAlphaToMask()
-                    self.bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    self.bmp.SetMask(mask)
-                    del tmp_image
-                    del mask
-                self.left = 0
-                self.right = self.bmp.GetWidth()
-                self.top = 0
-                self.bottom = self.bmp.GetHeight()
-                # grey outline
-                graypen = wx.Pen("gray", 1, wx.DOT)
-                dc.SetPen(graypen)
-                dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                #if width or height < 20 then offset = 1
-                if self.bmp.GetWidth() <= 20: xoffset = 1
-                else: xoffset = 5
-                if self.bmp.GetHeight() <= 20: yoffset = 1
-                else: yoffset = 5
-                dc.DrawRectangle(self.pos.x + xoffset, 
-                    self.pos.y + yoffset, self.bmp.GetWidth() - (xoffset * 2), 
-                    self.bmp.GetHeight() - (yoffset * 2))
-                dc.SetBrush(wx.NullBrush)
-                dc.SetPen(wx.NullPen)
-                ## draw label in the center of the mini
-                label = mini_layer.get_mini_label(self)
-                if len(label):
-                    dc.SetTextForeground(wx.RED)
-                    (textWidth,textHeight) = dc.GetTextExtent(label)
-                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
-                    y = self.pos.y + (self.bmp.GetHeight() / 2)
-                    dc.SetPen(wx.GREY_PEN)
-                    dc.SetBrush(wx.LIGHT_GREY_BRUSH)
-                    dc.DrawRectangle(x, y, textWidth+2, textHeight+2)
-                    if (textWidth+2 > self.right):
-                        self.right += int((textWidth+2-self.right)/2)+1
-                        self.left -= int((textWidth+2-self.right)/2)+1
-                    self.bottom = y+textHeight+2-self.pos.y
-                    dc.SetPen(wx.NullPen)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.DrawText(label, x+1, y+1)
-
-                #selected outline
-                if self.selected:
-                    dc.SetPen(wx.RED_PEN)
-                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                return True
-            elif self.hide: return True
-
-            else:
-                # set the width and height of the image
-                bmp = self.bmp
-                if self.width and self.height:
-                    tmp_image = self.bmp.ConvertToImage()
-                    tmp_image.Rescale(int(self.width), int(self.height))
-                    tmp_image.ConvertAlphaToMask()
-                    self.bmp = tmp_image.ConvertToBitmap()
-                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), 
-                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
-                    self.bmp.SetMask(mask)
-                    if self.gray:
-                        tmp_image = tmp_image.ConvertToGreyscale()
-                        bmp = tmp_image.ConvertToBitmap()
-                    else: bmp = self.bmp
-
-                if self.rotate != 0:
-                    x = bmp.GetWidth(); print x
-                    y = bmp.GetHeight(); print y
-                    img = bmp.ConvertToImage()
-                    img = img.Rotate(self.rotate, (3, 80), True)
-                    img.ConvertAlphaToMask()
-
-                    bmp = img.ConvertToBitmap()
-                    mask = wx.Mask(bmp, wx.Colour(img.GetMaskRed(), 
-                        img.GetMaskGreen(), img.GetMaskBlue()))
-                    bmp.SetMask(mask)
-
-                dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
-                component.get('drawn')[bmp] = True
-                self.left = 0
-                self.right = self.bmp.GetWidth()
-                self.top = 0
-                self.bottom = self.bmp.GetHeight()
-
-                # Draw the heading if needed
-                if self.heading:
-                    x_adjust = 0
-                    y_adjust = 4
-                    x_half = self.bmp.GetWidth()/2
-                    y_half = self.bmp.GetHeight()/2
-                    x_quarter = self.bmp.GetWidth()/4
-                    y_quarter = self.bmp.GetHeight()/4
-                    x_3quarter = x_quarter*3
-                    y_3quarter = y_quarter*3
-                    x_full = self.bmp.GetWidth()
-                    y_full = self.bmp.GetHeight()
-                    x_center = self.pos.x + x_half
-                    y_center = self.pos.y + y_half
-                    # Remember, the pen/brush must be a different color than the
-                    # facing marker!!!!  We'll use black/cyan for starters.
-                    # Also notice that we will draw the heading on top of the
-                    # larger facing marker.
-                    dc.SetPen(wx.BLACK_PEN)
-                    dc.SetBrush(wx.CYAN_BRUSH)
-                    triangle = []
-
-                    # Figure out which direction to draw the marker!!
-                    if self.heading == FACE_NORTH:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
-                        triangle.append(cmpPoint(x_center, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
-                    elif self.heading ==  FACE_SOUTH:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
-                        triangle.append(cmpPoint(x_center, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
-                    elif self.heading == FACE_NORTHEAST:
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
-                    elif self.heading == FACE_EAST:
-                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center ))
-                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
-                    elif self.heading == FACE_SOUTHEAST:
-                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
-                        triangle.append(cmpPoint(x_center + x_3quarter, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
-                    elif self.heading == FACE_SOUTHWEST:
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center + y_3quarter ))
-                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
-                    elif self.heading == FACE_WEST:
-                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center ))
-                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
-                    elif self.heading == FACE_NORTHWEST:
-                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
-                        triangle.append(cmpPoint(x_center - x_3quarter, y_center - y_3quarter ))
-                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
-                    dc.DrawPolygon(triangle)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                #selected outline
-                if self.selected:
-                    dc.SetPen(wx.RED_PEN)
-                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
-                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
-                    dc.SetBrush(wx.NullBrush)
-                    dc.SetPen(wx.NullPen)
-                # draw label
-                label = mini_layer.get_mini_label(self)
-                if len(label):
-                    dc.SetTextForeground(wx.RED)
-                    (textWidth,textHeight) = dc.GetTextExtent(label)
-                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
-                    y = self.pos.y + self.bmp.GetHeight() + 6
-                    dc.SetPen(wx.WHITE_PEN)
-                    dc.SetBrush(wx.WHITE_BRUSH)
-                    dc.DrawRectangle(x,y,textWidth+2,textHeight+2)
-                    if (textWidth+2 > self.right):
-                        self.right += int((textWidth+2-self.right)/2)+1
-                        self.left -= int((textWidth+2-self.right)/2)+1
-                    self.bottom = y+textHeight+2-self.pos.y
-                    dc.SetPen(wx.NullPen)
-                    dc.SetBrush(wx.NullBrush)
-                    dc.DrawText(label,x+1,y+1)
-                self.top-=5
-                self.bottom+=5
-                self.left-=5
-                self.right+=5
-                return True
-        else: return False
-
-    def toxml(self, action="update"):
-        if action == "del":
-            xml_str = "<token action='del' id='" + self.id + "'/>"
-            return xml_str
-        xml_str = "<token"
-        xml_str += " action='" + action + "'"
-        xml_str += " label='" + self.label + "'"
-        xml_str+= " id='" + self.id + "'"
-        if self.pos != None:
-            xml_str += " posx='" + str(self.pos.x) + "'"
-            xml_str += " posy='" + str(self.pos.y) + "'"
-        if self.heading != None: xml_str += " heading='" + str(self.heading) + "'"
-        if self.rotate != None: xml_str += " rotate='" + str(self.rotate) + "'"
-        if self.path != None: xml_str += " path='" + urllib.quote(self.path).replace('%3A', ':') + "'"
-        if self.locked: xml_str += "  locked='1'"
-        else: xml_str += "  locked='0'"
-        if self.hide: xml_str += " hide='1'"
-        else: xml_str += " hide='0'"
-        if self.snap_to_align != None: xml_str += " align='" + str(self.snap_to_align) + "'"
-        if self.id != None: xml_str += " zorder='" + str(self.zorder) + "'"
-        if self.width != None: xml_str += " width='" + str(self.width) + "'"
-        if self.height != None: xml_str += " height='" + str(self.height) + "'"
-        if self.local:
-            xml_str += ' local="' + str(self.local) + '"'
-            xml_str += ' localPath="' + str(urllib.quote(self.localPath).replace('%3A', ':')) + '"'
-            xml_str += ' localTime="' + str(self.localTime) + '"'
-        xml_str += " />"
-        if (action == "update" and self.isUpdated) or action == "new":
-            self.isUpdated = False
-            return xml_str
-        else: return ''
-
-    def takedom(self, xml_dom):
-        self.id = xml_dom.getAttribute("id")
-        if xml_dom.hasAttribute("posx"):
-            self.pos.x = int(xml_dom.getAttribute("posx"))
-        if xml_dom.hasAttribute("posy"):
-            self.pos.y = int(xml_dom.getAttribute("posy"))
-        if xml_dom.hasAttribute("heading"):
-            self.heading = int(xml_dom.getAttribute("heading"))
-        if xml_dom.hasAttribute("rotate"):
-            self.rotate = int(xml_dom.getAttribute("rotate"))
-        if xml_dom.hasAttribute("path"):
-            self.path = urllib.unquote(xml_dom.getAttribute("path"))
-            self.set_bmp(ImageHandler.load(self.path, 'token', self.id))
-        if xml_dom.hasAttribute("locked"):
-            if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True': self.locked = True
-            else: self.locked = False
-        if xml_dom.hasAttribute("hide"):
-            if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True': self.hide = True
-            else: self.hide = False
-        if xml_dom.hasAttribute("label"):
-            self.label = xml_dom.getAttribute("label")
-        if xml_dom.hasAttribute("zorder"):
-            self.zorder = int(xml_dom.getAttribute("zorder"))
-        if xml_dom.hasAttribute("align"):
-            if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True': self.snap_to_align = 1
-            else: self.snap_to_align = 0
-        if xml_dom.hasAttribute("width"):
-            self.width = int(xml_dom.getAttribute("width"))
-        if xml_dom.hasAttribute("height"):
-            self.height = int(xml_dom.getAttribute("height"))
-
-##-----------------------------
-## token layer
-##-----------------------------
-class token_layer(layer_base):
-    def __init__(self, canvas):
-        self.canvas = canvas
-        layer_base.__init__(self)
-        self.id = -1 #added.
-        self.tokens = []
-        self.serial_number = 0
-
-        self.drawn = {}
-        component.add('drawn', self.drawn)
-        # Set the font of the labels to be the same as the chat window
-        # only smaller.
-        font_size = int(settings.get_setting('defaultfontsize'))
-        if (font_size >= 10): font_size -= 2
-        self.label_font = wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL,
-                                  False, settings.get_setting('defaultfont'))
-
-    def next_serial(self):
-        self.serial_number += 1
-        return self.serial_number
-
-    def get_next_highest_z(self):
-        z = len(self.tokens)+1
-        return z
-
-    def cleanly_collapse_zorder(self):
-        #  lock the zorder stuff
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        i = 0
-        for mini in sorted_tokens:
-            mini.zorder = i
-            i = i + 1
-        #  unlock the zorder stuff
-
-    def collapse_zorder(self):
-        #  lock the zorder stuff
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        i = 0
-        for mini in sorted_tokens:
-            if (mini.zorder != MIN_STICKY_BACK) and (mini.zorder != MIN_STICKY_FRONT): mini.zorder = i
-            else: pass
-            i = i + 1
-        #  unlock the zorder stuff
-
-    def rollback_serial(self):
-        self.serial_number -= 1
-
-    def add_token(self, id, path, pos=cmpPoint(0,0), label="", heading=FACE_NONE, 
-            rotate=0, width=0, height=0, local=False, localPath='', localTime=-1):
-        bmp = ImageHandler.load(path, 'token', id)
-        if bmp:
-            mini = BmpToken(id, path, bmp, pos, heading, rotate, label, 
-                zorder=self. get_next_highest_z(), width=width, 
-                height=height, local=local, localPath=localPath, localTime=localTime)
-            self.tokens.append(mini)
-            self.drawn[mini.bmp] = False
-            xml_str = "<map><tokens>"
-            xml_str += mini.toxml("new")
-            xml_str += "</tokens></map>"
-            component.get('session').send(xml_str)
-
-    def get_token_by_id(self, id):
-        for mini in self.tokens:
-            if str(mini.id) == str(id):
-                return mini
-        return None
-
-    def del_token(self, min):
-        xml_str = "<map><tokens>"
-        xml_str += min.toxml("del")
-        xml_str += "</tokens></map>"
-        self.canvas.frame.session.send(xml_str)
-        self.tokens.remove(min)
-        del min
-        self.collapse_zorder()
-
-    def del_all_tokens(self):
-        while len(self.tokens):
-            min = self.tokens.pop()
-            del min
-        self.collapse_zorder()
-
-    def layerDraw(self, dc, topleft, size):
-        dc.SetFont(self.label_font)
-        sorted_tokens = self.tokens[:]
-        sorted_tokens.sort(cmp_zorder)
-        for m in sorted_tokens:
-            if (m.pos.x>topleft[0]-m.right and
-                m.pos.y>topleft[1]-m.bottom and
-                m.pos.x<topleft[0]+size[0]-m.left and
-                m.pos.y<topleft[1]+size[1]-m.top):
-                """
-                if self.drawn.has_key(m.bmp):
-                    if self.drawn[m.bmp] == True:
-                        dc2 = wx.MemoryDC()
-                        img = m.bmp.ConvertToImage()
-                        bmp = img.ConvertToBitmap()
-
-                        dc2.SelectObject(bmp)
-                        dc.Blit(m.pos.x, m.pos.y, img.GetHeight(), img.GetWidth(), dc2, 0, 0, wx.COPY, True, 0, 0)
-                        del dc2
-                
-                else:
-                """
-                m.draw(dc, self)
-
-    def find_token(self, pt, only_unlocked=False):
-        min_list = []
-        for m in self.tokens:
-            if m.hit_test(pt):
-                if m.hide and self.canvas.frame.session.my_role() != self.canvas.frame.session.ROLE_GM: continue
-                if only_unlocked and not m.locked: min_list.append(m)
-                elif not only_unlocked and m.locked: min_list.append(m)
-                else: continue
-        if len(min_list) > 0:
-            return min_list
-        else: return None
-
-    def layerToXML(self, action="update"):
-        """ format  """
-        minis_string = ""
-        if self.tokens:
-            for m in self.tokens: minis_string += m.toxml(action)
-        if minis_string != '':
-            s = "<tokens"
-            s += " serial='" + str(self.serial_number) + "'"
-            s += ">"
-            s += minis_string
-            s += "</tokens>"
-            return s
-        else: return ""
-
-    def layerTakeDOM(self, xml_dom):
-        if xml_dom.hasAttribute('serial'):
-            self.serial_number = int(xml_dom.getAttribute('serial'))
-        children = xml_dom._get_childNodes()
-        for c in children:
-            action = c.getAttribute("action")
-            id = c.getAttribute('id')
-            if action == "del": 
-                mini = self.get_token_by_id(id)
-                if mini:
-                    self.tokens.remove(mini)
-                    del mini
-            elif action == "new":
-                pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy')))
-                path = urllib.unquote(c.getAttribute('path'))
-                label = c.getAttribute('label')
-                height = width = heading = rotate = snap_to_align = zorder = 0
-                locked = hide = False
-                if c.hasAttribute('height'): height = int(c.getAttribute('height'))
-                if c.hasAttribute('width'): width = int(c.getAttribute('width'))
-                if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1': locked = True
-                if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1': hide = True
-                if c.getAttribute('heading'): heading = int(c.getAttribute('heading'))
-                if c.hasAttribute('rotate'): rotate = int(c.getAttribute('rotate'))
-                if c.hasAttribute('align'): snap_to_align = int(c.getAttribute('align'))
-                if c.getAttribute('zorder'): zorder = int(c.getAttribute('zorder'))
-                min = BmpToken(id, path, ImageHandler.load(path, 'token', id), pos, heading, 
-                    rotate, label, locked, hide, snap_to_align, zorder, width, height)
-                self.tokens.append(min)
-                if c.hasAttribute('local') and c.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(c.getAttribute('localPath'))):
-                    localPath = urllib.unquote(c.getAttribute('localPath'))
-                    local = True
-                    localTime = float(c.getAttribute('localTime'))
-                    if localTime-time.time() <= 144000:
-                        file = open(localPath, "rb")
-                        imgdata = file.read()
-                        file.close()
-                        filename = os.path.split(localPath)
-                        (imgtype,j) = mimetypes.guess_type(filename[1])
-                        postdata = urllib.urlencode({'filename':filename[1], 'imgdata':imgdata, 'imgtype':imgtype})
-                        thread.start_new_thread(self.upload, (postdata, localPath, True))
-                #  collapse the zorder.  If the client behaved well, then nothing should change.
-                #    Otherwise, this will ensure that there's some kind of z-order
-                self.collapse_zorder()
-            else:
-                mini = self.get_token_by_id(id)
-                if mini: mini.takedom(c)
-
-    def upload(self, postdata, filename, modify=False, pos=cmpPoint(0,0)):
-        self.lock.acquire()
-        url = settings.get_setting('ImageServerBaseURL')
-        file = urllib.urlopen(url, postdata)
-        recvdata = file.read()
-        file.close()
-        try:
-            xml_dom = minidom.parseString(recvdata)._get_documentElement()
-            if xml_dom.nodeName == 'path':
-                path = xml_dom.getAttribute('url')
-                path = urllib.unquote(path)
-                if not modify:
-                    start = path.rfind("/") + 1
-                    if self.canvas.parent.layer_handlers[2].auto_label: min_label = path[start:len(path)-4]
-                    else: min_label = ""
-                    id = 'mini-' + self.canvas.frame.session.get_next_id()
-                    self.add_token(id, path, pos=pos, label=min_label, local=True, 
-                        localPath=filename, localTime=time.time())
-                else:
-                    self.tokens[len(self.tokens)-1].local = True
-                    self.tokens[len(self.tokens)-1].localPath = filename
-                    self.tokens[len(self.tokens)-1].localTime = time.time()
-                    self.tokens[len(self.tokens)-1].path = path
-            else:
-                print xml_dom.getAttribute('msg')
-        except Exception, e:
-            print e
-            print recvdata
-        urllib.urlcleanup()
-        self.lock.release()
-####################################################################
-        ## helper function
-
-    def get_mini_label(self, mini):
-        # override this to change the label displayed under each mini (and the label on hidden minis)
-        return mini.label
--- a/plugins/bcg/tokens_msg.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-# Copyright (C) 2000-2001 The OpenRPG Project
-#
-#    openrpg-dev@lists.sourceforge.net
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# --
-#
-# File: mapper/tokens_msg.py
-# Author: Chris Davis
-# Maintainer:
-# Version:
-#   $Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
-#
-# Description: This file contains some of the basic definitions for the chat
-# utilities in the orpg project.
-#
-__version__ = "$Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
-
-from base_msg import *
-
-class mini_msg(map_element_msg_base):
-
-    def __init__(self,reentrant_lock_object = None):
-        self.tagname = "token"   # set this to be for minis.  Tagname gets used in some base class functions.
-        map_element_msg_base.__init__(self,reentrant_lock_object)   # call base class
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element containing only the changes to this mini
-    def standalone_update_text(self,update_id_string):
-        buffer = "<map id='" + update_id_string + "'>"
-        buffer += "<tokens>"
-        buffer += self.get_changed_xml()
-        buffer += "</tokens></map>"
-        return buffer
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element that deletes this mini
-    def standalone_delete_text(self,update_id_string):
-        buffer = None
-        if self._props.has_key("id"):
-            buffer = "<map id='" + update_id_string + "'>"
-            buffer += "<tokens>"
-            buffer += "<token action='del' id='" + self._props("id") + "'/>"
-            buffer += "</tokens></map>"
-        return buffer
-
-    # convenience method to use if only this mini is modified
-    #   outputs a <map/> element to add this mini
-    def standalone_add_text(self,update_id_string):
-        buffer = "<map id='" + update_id_string + "'>"
-        buffer += "<tokens>"
-        buffer += self.get_all_xml()
-        buffer += "</tokens></map>"
-        return buffer
-
-    def get_all_xml(self,action="new",output_action=1):
-        return map_element_msg_base.get_all_xml(self,action,output_action)
-
-    def get_changed_xml(self,action="update",output_action=1):
-        return map_element_msg_base.get_changed_xml(self,action,output_action)
-
-class minis_msg(map_element_msg_base):
-
-    def __init__(self,reentrant_lock_object = None):
-        self.tagname = "tokens"
-        map_element_msg_base.__init__(self,reentrant_lock_object)
-
-    def init_from_dom(self,xml_dom):
-        self.p_lock.acquire()
-        if xml_dom.tagName == self.tagname:
-            if xml_dom.getAttributeKeys():
-                for k in xml_dom.getAttributeKeys():
-                    self.init_prop(k,xml_dom.getAttribute(k))
-
-            for c in xml_dom._get_childNodes():
-                mini = mini_msg(self.p_lock)
-                try: mini.init_from_dom(c)
-                except Exception, e: print e; continue
-                id = mini.get_prop("id")
-                action = mini.get_prop("action")
-
-                if action == "new": self.children[id] = mini
-                elif action == "del":
-                    if self.children.has_key(id):
-                        self.children[id] = None
-                        del self.children[id]
-
-                elif action == "update":
-                    if self.children.has_key(id):
-                        self.children[id].init_props(mini.get_all_props())
-        else:
-            self.p_lock.release()
-            raise Exception, "Error attempting to initialize a " + self.tagname + " from a non-<" + self.tagname + "/> element"
-        self.p_lock.release()
-
-    def set_from_dom(self,xml_dom):
-        self.p_lock.acquire()
-        if xml_dom.tagName == self.tagname:
-            if xml_dom.getAttributeKeys():
-                for k in xml_dom.getAttributeKeys():
-                    self.set_prop(k,xml_dom.getAttribute(k))
-
-            for c in xml_dom._get_childNodes():
-                mini = mini_msg(self.p_lock)
-
-                try: mini.set_from_dom(c)
-                except Exception, e: print e; continue
-                id = mini.get_prop("id")
-                action = mini.get_prop("action")
-                if action == "new": self.children[id] = mini
-                elif action == "del":
-                    if self.children.has_key(id):
-                        self.children[id] = None
-                        del self.children[id]
-                elif action == "update":
-                    if self.children.has_key(id):
-                        self.children[id].set_props(mini.get_all_props())
-        else:
-            self.p_lock.release()
-            raise Exception, "Error attempting to set a " + self.tagname + " from a non-<" + self.tagname + "/> element"
-        self.p_lock.release()
--- a/plugins/xxbcg.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-import os
-import sys
-import orpg.pluginhandler
-from orpg.mapper.map import *
-from orpg.orpgCore import component
-import wx
-
-from orpg.mapper.images import ImageHandler
-from orpg.mapper.whiteboard_handler import *
-from orpg.mapper.background_handler import *
-from orpg.mapper.grid_handler import *
-from orpg.mapper.map_handler import *
-from orpg.mapper.fog_handler import *
-
-from bcg.token_handler import *
-from bcg.tokens import *
-
-
-class Plugin(orpg.pluginhandler.PluginHandler):
-    # Initialization subroutine.
-    #
-    # !self : instance of self
-    # !openrpg : instance of the the base openrpg control
-    def __init__(self, plugindb, parent):
-        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
-
-        # The Following code should be edited to contain the proper information
-        self.name = 'Board / Card Game'
-        self.author = 'Tyler Starke (Prof. Ebral)'
-        self.help = 'Start Here'
-        self.parent = parent
-        #You can set variables below here. Always set them to a blank value in this section. Use plugin_enabled
-        #to set their proper values.
-        self.sample_variable = {}
-
-        self.canvas = component.get('map').canvas ## Obtain MapCanvas
-
-    def plugin_enabled(self):
-        tabs = component.get('map_tabs')
-        layers = component.get('map_layers')
-        map_wnd = component.get('map_wnd')
-        pages = tabs.GetPageCount()
-        self.layers = []
-        while pages:
-            pages -= 1
-            if tabs.GetPageText(pages) != 'Background':
-                if tabs.GetPageText(pages) != 'Whiteboard': 
-                    tabs.RemovePage(pages)
-        #tabs.InsertPage(2, layers[0], 'Tiles') # Removed for testing.
-        map_wnd.handlers[6]=(token_handler(tabs, -1, map_wnd.canvas))
-        tabs.InsertPage(3, map_wnd.handlers[6], 'Tokens')
-
-        ## Re Direct MapCanvas OnPaint event.
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
-        self.canvas.Bind(wx.EVT_PAINT, self.on_paint)
-
-        ## Add to MapCanvas proccessImages
-        self.canvas.Bind(wx.EVT_TIMER, self.processImages, self.canvas.image_timer)
-
-        ## Create Token Layer
-        self.canvas.layers['token'] = token_layer(self.canvas)
-        #self.canvas.layers['tiles'] = tile_layer(self.canvas) #Not ready.
-
-        ### Define Grid / Background
-        self.canvas.layers['grid'].snap = False
-        self.canvas.layers['grid'].line = 0
-        #self.canvas.layers['bg'].set_texture(component.get('cherrypy')+'Textures/versa_anigre.jpg')
-        pass
-
-    def processImages(self, evt=None):
-        self.session = component.get("session")
-        if self.session.my_role() == self.session.ROLE_LURKER or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            cidx = self.canvas.parent.get_tab_index("Tiles")
-            self.canvas.parent.tabs.EnableTab(cidx, False)
-            cidx = self.canvas.parent.get_tab_index("Tokens")
-            self.canvas.parent.tabs.EnableTab(cidx, False)
-        else:
-            cidx = self.canvas.parent.get_tab_index("Tiles")
-            self.canvas.parent.tabs.EnableTab(cidx, True)
-            cidx = self.canvas.parent.get_tab_index("Tokens")
-            self.canvas.parent.tabs.EnableTab(cidx, True)
-        if not self.canvas.cacheSizeSet:
-            self.canvas.cacheSizeSet = True
-            cacheSize = component.get('settings').get_setting("ImageCacheSize")
-            if len(cacheSize): self.canvas.cacheSize = int(cacheSize)
-            else: pass
-        if not ImageHandler.Queue.empty():
-            (path, image_type, imageId) = ImageHandler.Queue.get()
-            img = wx.ImageFromMime(path[1], path[2]).ConvertToBitmap()
-            try:
-                # Now, apply the image to the proper object
-                if image_type == "miniature":
-                    min = self.canvas.layers['miniatures'].get_miniature_by_id(imageId)
-                    min.set_bmp(img)
-                elif image_type == "background" or image_type == "texture":
-                    self.canvas.layers['bg'].bg_bmp = img
-                    if image_type == "background": self.canvas.set_size([img.GetWidth(), img.GetHeight()])
-                elif image_type == "token":
-                    min = self.canvas.layers['token'].get_token_by_id(imageId)
-                    min.set_bmp(img)
-            except: pass
-
-    def on_paint(self, evt):
-        if self.canvas.layers.has_key('token') == False: self.canvas.layers['token'] = token_layer(self.canvas)
-        print 'BCG onpaint'
-        scale = self.canvas.layers['grid'].mapscale
-        scrollsize = self.canvas.GetScrollPixelsPerUnit()
-        clientsize = self.canvas.GetClientSize()
-        topleft1 = self.canvas.GetViewStart()
-        topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]]
-        if (clientsize[0] > 1) and (clientsize[1] > 1):
-            dc = wx.MemoryDC()
-            bmp = wx.EmptyBitmap(clientsize[0]+1, clientsize[1]+1)
-            dc.SelectObject(bmp)
-            dc.SetPen(wx.TRANSPARENT_PEN)
-            dc.SetBrush(wx.Brush(self.canvas.GetBackgroundColour(), wx.SOLID))
-            dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1)
-            dc.SetDeviceOrigin(-topleft[0], -topleft[1])
-            dc.SetUserScale(scale, scale)
-            self.canvas.layers['bg'].layerDraw(dc, scale, topleft, clientsize)
-            self.canvas.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
-                [clientsize[0]/scale, clientsize[1]/scale])
-
-
-            self.canvas.layers['token'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
-                [clientsize[0]/scale, clientsize[1]/scale])
-
-
-            self.canvas.layers['whiteboard'].layerDraw(dc)
-            self.canvas.layers['fog'].layerDraw(dc, topleft, clientsize)
-            dc.SetPen(wx.NullPen)
-            dc.SetBrush(wx.NullBrush)
-            dc.SelectObject(wx.NullBitmap)
-            del dc
-            wdc = self.canvas.preppaint()
-            wdc.DrawBitmap(bmp, topleft[0], topleft[1])
-            if settings.get_setting("AlwaysShowMapScale") == "1":
-                self.canvas.showmapscale(wdc)
-        try: evt.Skip()
-        except: pass
-
-    def plugin_disabled(self):
-        tabs = component.get('map_tabs')
-        map_wnd = component.get('map_wnd')
-        pages = tabs.GetPageCount()
-        while pages:
-            pages -= 1
-            if tabs.GetPageText(pages) != 'Background':
-                if tabs.GetPageText(pages) != 'Whiteboard': 
-                    tabs.RemovePage(pages)
-        layers = component.get('map_layers')
-        tabs.InsertPage(1, layers[1],"Grid")
-        tabs.InsertPage(2, layers[2],"Miniatures")
-        tabs.InsertPage(4, layers[4],"Fog")
-        tabs.InsertPage(5, layers[5],"General")
-        map_wnd.current_layer = 2
-        map_wnd.tabs.SetSelection(map_wnd.current_layer)
-    
-        ## Re Connect original MapCanvas OnPaint event.
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
-        self.canvas.Bind(wx.EVT_PAINT, self.canvas.on_paint)
-
-        ## Disconnect new proccessImages addition
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_TIMER)
-        self.canvas.Bind(wx.EVT_TIMER, self.canvas.processImages, self.canvas.image_timer)
-
-        self.canvas.layers['grid'].snap = True
-        self.canvas.layers['grid'].line = 1
-
-        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
-        #such as closing windows created by the plugin
-        #self.plugin_removecmd('/test')
-        #self.plugin_removecmd('/example')
-
-        #This is the command to delete a message handler
-        #self.plugin_delete_msg_handler('xxblank')
-
-        #This is how you should destroy a frame when the plugin is disabled
-        #This same method should be used in close_module as well
-        try:
-            self.frame.Destroy()
-        except:
-            pass
-
-    def on_test(self, cmdargs):
-        #this is just an example function for a command you create.
-        # cmdargs contains everything you typed after the command
-        # so if you typed /test this is a test, cmdargs = this is a test
-        # args are the individual arguments split. For the above example
-        # args[0] = this , args[1] = is , args[2] = a , args[3] = test
-        self.plugin_send_msg(cmdargs, '<xxblank>' + cmdargs + '</xxblank>')
-        args = cmdargs.split(None,-1)
-        msg = 'cmdargs = %s' % (cmdargs)
-        self.chat.InfoPost(msg)
-
-        if len(args) == 0:
-            self.chat.InfoPost("You have no args")
-        else:
-            i = 0
-            for n in args:
-                msg = 'args[' + str(i) + '] = ' + n
-                self.chat.InfoPost(msg)
-                i += 1
-
-    def on_xml_recive(self,id, data,xml_dom):
-        self.chat.InfoPost(self.name + ":: Message recived<br />" + data.replace("<","&lt;").replace(">","&gt;") +'<br />From id:' + str(id))
-
-    def pre_parse(self, text):
-        #This is called just before a message is parsed by openrpg
-        return text
-
-    def send_msg(self, text, send):
-        #This is called when a message is about to be sent out.
-        #It covers all messages sent by the user, before they have been formatted.
-        #If send is set to 0, the message will not be sent out to other
-        #users, but it will still be posted to the user's chat normally.
-        #Otherwise, send defaults to 1. (The message is sent as normal)
-        return text, send
-
-    def plugin_incoming_msg(self, text, type, name, player):
-        #This is called whenever a message from someone else is received, no matter
-        #what type of message it is.
-        #The text variable is the text of the message. If the type is a regular
-        #message, it is already formatted. Otherwise, it's not.
-        #The type variable is an integer which tells you the type: 1=chat, 2=whisper
-        #3=emote, 4=info, and 5=system.
-        #The name variable is the name of the player who sent you the message.
-        #The player variable contains lots of info about the player sending the
-        #message, including name, ID#, and currently-set role.
-        #Uncomment the following line to see the format for the player variable.
-        #print player
-        return text, type, name
-
-    def post_msg(self, text, myself):
-        #This is called whenever a message from anyone is about to be posted
-        #to chat; it doesn't affect the copy of the message that gets sent to others
-        #Be careful; system and info messages trigger this too.
-        return text
-
-    def refresh_counter(self):
-        #This is called once per second. That's all you need to know.
-        pass
--- a/plugins/xxblank.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxblank.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,4 +1,4 @@
-import os
+import os, wx
 import orpg.pluginhandler
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -18,6 +18,16 @@
         #to set their proper values.
         self.sample_variable = {}
 
+    def plugin_menu(self):
+        ## This is a standardized Menu item.  It connects to plugin_toggle where you can set events.
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
+
 
     def plugin_enabled(self):
         #You can add new /commands like
--- a/plugins/xxchatnotify.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxchatnotify.py	Sat Apr 24 08:37:20 2010 -0500
@@ -126,14 +126,15 @@
 
 
     def plugin_incoming_msg(self, text, type, name, player):
-        if (self.notify == 'beep' or self.notify == 'both') and (self.type == 'all' or type == 2):
-            if self.soundfile == 'None':
-                wx.CallAfter(wx.Bell)
-                wx.CallAfter(wx.Bell)
-            else:
-                wx.CallAfter(self.sound_player.play, self.soundfile, self.soundloc)
-        if (self.notify == 'flash' or self.notify == 'both') and (self.type == 'all' or type == 2):
-            wx.CallAfter(self.mainframe.RequestUserAttention)
+        if not self.topframe.IsActive():
+            if (self.notify == 'beep' or self.notify == 'both') and (self.type == 'all' or type == 2):
+                if self.soundfile == 'None':
+                    wx.CallAfter(wx.Bell)
+                    wx.CallAfter(wx.Bell)
+                else:
+                    wx.CallAfter(self.sound_player.play, self.soundfile, self.soundloc)
+            if (self.notify == 'flash' or self.notify == 'both') and (self.type == 'all' or type == 2):
+                wx.CallAfter(self.mainframe.RequestUserAttention)
         return text, type, name
 
 
--- a/plugins/xxgsc.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxgsc.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,9 +1,7 @@
-import os
-from orpg.orpg_wx import *
+import os, wx
 import random
 import orpg.pluginhandler
 
-
 ID_ROLL = wx.NewId()
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -15,7 +13,7 @@
         orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
 
         self.name = 'Game Status Controller'
-        self.author = 'Woody, updated by mDuo13'
+        self.author = 'Woody, updated by mDuo13 and Calchexas'
         self.help = 'This plugin lets you quickly and easily manage a status that includes \n'
         self.help += 'your HP and AC for AD&D 2nd Edition. Type /gsc to open up the manager\n'
         self.help += 'window, and from there just change the values as necessary and the changes\n'
@@ -26,12 +24,14 @@
 
     def plugin_enabled(self):
         self.plugin_addcommand('/gsc', self.on_gsc, '- The GSC command')
-        self.frame = RollerFrame(None, -1, "Game Status Ctrl (GSC)", self)
+        self.frame = RollerFrame(None, -1, "Game Status Controller (GSC)", self)
         self.frame.Hide()
 
-        item = wx.MenuItem(self.menu, wx.ID_ANY, "GSC Window", "GSC Window", wx.ITEM_CHECK)
-        self.topframe.Bind(wx.EVT_MENU, self._toggleWindow, item)
-        self.menu.AppendItem(item)
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'GSC Window')
+        self.topframe.Bind(wx.EVT_MENU, self._toggleWindow, self.toggle)
+        self.toggle.Check(False)
 
     def plugin_disabled(self):
         self.plugin_removecmd('/gsc')
@@ -48,26 +48,26 @@
 
     #Events
     def _toggleWindow(self, evt):
-        id = evt.GetId()
-        item = self.menu.FindItemById(id)
         if self.frame.IsShown():
             self.frame.Hide()
-            item.Check(False)
+            self.toggle.Check(False)
         else:
             self.frame.Show()
-            item.Check(True)
+            self.toggle.Check(True)
 
 
 class RollerFrame(wx.Frame):
     def __init__(self, parent, ID, title, plugin):
         wx.Frame.__init__(self, parent, ID, title,
-                         wx.DefaultPosition, wx.Size(200, 70))
+                         wx.DefaultPosition, wx.Size(250, 110))
 
         self.settings = plugin.settings
         self.session = plugin.session
         self.plugin = plugin
 
         self.panel = wx.Panel(self,-1)
+        sizer = wx.GridBagSizer(1, 2)
+        self.panel.SetSizer(sizer)
         menu = wx.Menu()
         menu.AppendSeparator()
         menu.Append(wx.ID_EXIT, "&Close", "Close this window")
@@ -77,18 +77,42 @@
 
         self.old_idle = self.settings.get_setting('IdleStatusAlias')
 
-        wx.StaticText(self.panel, -1, "AC:", wx.Point(0, 5))
-        self.ac = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(18, 0), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        ac_text = wx.StaticText(self.panel, -1, "AC:", wx.Point(0, 5))
+        self.ac = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(18, 0), wx.Size(45, -1), min = -100, max = 100, initial = 10)
         self.ac.SetValue(10)
 
-        wx.StaticText(self.panel, -1, "/", wx.Point(136, 5))
-        self.max_hp = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(144, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
+        touch_text = wx.StaticText(self.panel, -1, "Touch:", wx.Point(0, 25))
+        self.touch = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(60, 25), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        self.touch.SetValue(10)
+
+        ff_text = wx.StaticText(self.panel, -1, "FF:", wx.Point(115, 25))
+        self.ff = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(165, 25), wx.Size(45, -1), min = -100, max = 100, initial = 10)
+        self.ff.SetValue(10)
+        
+        max_hp_text = wx.StaticText(self.panel, -1, "/", wx.Point(150, 5))
+        self.max_hp = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(158, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
         self.max_hp.SetValue(10)
 
-        wx.StaticText(self.panel, -1, "HP:", wx.Point(65, 5))
-        self.hp = wx.SpinCtrl(self.panel, ID_ROLL, "", wx.Point(83, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
+        hp_text = wx.StaticText(self.panel, -1, "HP:", wx.Point(80, 5))
+        self.hp = wx.SpinCtrl(self.panel, ID_ROLL, "", 
+                                wx.Point(98, 0), wx.Size(48, -1), min = -999, max = 999, initial = 10)
         self.hp.SetValue(10)
 
+        sizer.Add(ac_text, (1,0), span=(1,1))
+        sizer.Add(self.ac, (1,1), span=(1,1))
+        sizer.Add(touch_text, (1,2), span=(1,1))
+        sizer.Add(self.touch, (1,3), span=(1,1))
+        sizer.Add(ff_text, (1,4), span=(1,1))
+        sizer.Add(self.ff, (1,5), span=(1,1))
+        sizer.Add(hp_text, (0,0), span=(1,1))
+        sizer.Add(self.hp, (0,1), span=(1,1))
+        sizer.Add(max_hp_text, (0,2), span=(1,1))
+        sizer.Add(self.max_hp, (0,3), span=(1,1))
+        self.SetMinSize((350,100))
         self.Bind(wx.EVT_SPINCTRL, self.SetStatus, id=ID_ROLL)
         self.Bind(wx.EVT_TEXT, self.SetStatus, id=ID_ROLL)
         self.Bind(wx.EVT_MENU, self.TimeToQuit, id=wx.ID_EXIT)
@@ -96,7 +120,7 @@
         self.SetStatus(None)
 
     def SetStatus(self, evt):
-        new_status = "AC: " + str(self.ac.GetValue()) + "   HP: " + str(self.hp.GetValue()) + "/" + str(self.max_hp.GetValue())
+        new_status = "AC: " + str(self.ac.GetValue()) + " (Touch: " + str(self.touch.GetValue()) + " FF: " + str(self.ff.GetValue()) + ")" + " HP: " + str(self.hp.GetValue()) + "/" + str(self.max_hp.GetValue())
         self.settings.set_setting('IdleStatusAlias',new_status)
         self.session.set_text_status(new_status)
 
--- a/plugins/xxhiddendice.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxhiddendice.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,5 +1,4 @@
-import os
-import re
+import os, re, wx
 import orpg.pluginhandler
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -23,32 +22,39 @@
         self.hiddenrolls = []
         self.dicere = "\{([0-9]*d[0-9]*.+)\}"
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
 
     def plugin_enabled(self):
         pass
 
-
     def plugin_disabled(self):
         pass
 
-
     def pre_parse(self, text):
-        m = re.search(self.dicere, text)
-        while m:
-            roll = "[" + m.group(1) + "]"
-            self.hiddenrolls += [self.chat.ParseDice(roll)]
-            text = text[:m.start()] + "(hidden roll)" + text[m.end():]
+        if self.toggle.IsChecked() == True:
             m = re.search(self.dicere, text)
+            while m:
+                roll = "[" + m.group(1) + "]"
+                self.hiddenrolls += [self.chat.ParseDice(roll)]
+                text = text[:m.start()] + "(hidden roll)" + text[m.end():]
+                m = re.search(self.dicere, text)
         return text
 
     def post_msg(self, text, myself):
-        c = 0
-        a = text.find("(hidden roll)")
-
-        while len(self.hiddenrolls) > c and a > -1:
-            text = text[:a+14].replace("(hidden roll)", self.hiddenrolls[c]) + text[a+14:]
+        if self.toggle.IsChecked() == True:
+            c = 0
             a = text.find("(hidden roll)")
-            c += 1
-        if c > 0:
-            self.hiddenrolls = []
+            while len(self.hiddenrolls) > c and a > -1:
+                text = text[:a+14].replace("(hidden roll)", self.hiddenrolls[c]) + text[a+14:]
+                a = text.find("(hidden roll)")
+                c += 1
+            if c > 0:
+                self.hiddenrolls = []
         return text
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/xxminiquicknote.py	Sat Apr 24 08:37:20 2010 -0500
@@ -0,0 +1,74 @@
+import os
+import orpg.pluginhandler
+from orpg.mapper.miniatures_handler import *
+from orpg.orpgCore import *
+import wx
+
+
+class QuickNoteDialog(wx.Dialog):
+    def __init__(self):
+        wx.Dialog.__init__(self, None, -1, "Quick Note", size=(250, 210))
+        self.text = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.text, 1, wx.EXPAND)
+        self.SetSizer(sizer)
+
+class Plugin(orpg.pluginhandler.PluginHandler):
+    def __init__(self, plugindb, parent):
+        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
+        self.name = 'Mini Quick Notes'
+        self.author = 'David'
+        self.help = """Allows you to add private notes when you right-click on a mini on the map.
+
+Note: it will try to save data between sessions but you must load plugin AFTER the map has been loaded
+so do not auto-load this plugin.  Also these notes are NOT shared with other users.
+
+Look at the mini superscript plugin for an example of how to do that.
+
+Modified for Traipse (Prof. Ebral)
+EXPERIMENTAL! In the process of being updated."""
+        self.save_on_exit = False;
+
+    def plugin_menu(self):
+        pass
+        
+    def plugin_enabled(self):
+        m = component.get("map").layer_handlers[2]
+        m.set_mini_rclick_menu_item("Quick Notes", self.on_quick_note)
+
+        db_notes_list = self.plugindb.GetList("xxminiquicknote", "notes", [])
+        matched = 0;
+        for mini in component.get("map").canvas.layers['miniatures'].miniatures:
+            print 'label:'+mini.label
+            print 'posx:'+str(mini.pos.x)
+            print 'posy:'+str(mini.pos.y)
+            for db_note in db_notes_list:
+                print 'db_note:'+str(db_note)
+                if mini.label == db_note[0] and mini.pos.x == db_note[1] and mini.pos.y == db_note[2]:
+                    mini.quicknote = db_note[3]
+                    db_notes_list.remove(db_note)
+                    matched += 1
+                    break
+
+    def plugin_disabled(self):
+        m = component.get("map").layer_handlers[2]
+        m.set_mini_rclick_menu_item("Quick Notes", None)
+
+        if self.save_on_exit:
+            db_notes_list = []
+            for mini in component.get("map").canvas.layers['miniatures'].miniatures:
+                if 'quicknote' in mini.__dict__:
+                    db_notes_list.append([mini.label, mini.pos.x, mini.pos.y, mini.quicknote])
+            self.plugindb.SetList("xxminiquicknote", "notes", db_notes_list)
+
+    def on_quick_note(self, event):
+        self.save_on_exit = True
+        m = component.get("map").layer_handlers[2]
+        # m.sel_rmin is the mini that was just right-clicked
+        if 'quicknote' not in m.sel_rmin.__dict__:
+            m.sel_rmin.quicknote = ''
+        dlg = QuickNoteDialog()
+        dlg.text.SetValue(m.sel_rmin.quicknote)
+        dlg.ShowModal()
+        m.sel_rmin.quicknote = dlg.text.GetValue()
+        dlg.Destroy()
--- a/plugins/xxmouse-zoom.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxmouse-zoom.py	Sat Apr 24 08:37:20 2010 -0500
@@ -19,6 +19,17 @@
         self.help += 'wheel and the map will zoom in or out.  And FAST too! \n'
         self.help += 'This plugin is designed for Grumpy Goblin and Ornery Orc.'
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        if self.toggle.IsChecked() == False: self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        if self.toggle.IsChecked() == True:
+            self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.MouseWheel)
+
     def plugin_enabled(self):
         try: self.canvas = component.get('map').canvas
         except: self.canvas = open_rpg.get_component('map').canvas
@@ -26,12 +37,12 @@
 
     def MouseWheel(self, evt):
         if evt.CmdDown():
-            print evt.GetWheelRotation()
             if evt.GetWheelRotation() > 0: self.canvas.on_zoom_in(None)
             elif evt.GetWheelRotation() < 0: self.canvas.on_zoom_out(None)
             else: pass
         else: self.canvas.on_scroll(evt)
 
     def plugin_disabled(self):
-        self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        try: self.canvas.Disconnect(-1, -1, wx.wxEVT_MOUSEWHEEL)
+        except: pass
 
--- a/plugins/xxspell.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxspell.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,4 +1,4 @@
-import os
+import os, wx
 import orpg.pluginhandler
 
 class Plugin(orpg.pluginhandler.PluginHandler):
@@ -17,6 +17,15 @@
         self.help += "even corrects other people's spelling."
         self.checklist = {}
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
+
     def plugin_enabled(self):
         #This is where you set any variables that need to be initalized when your plugin starts
         #You can add new /commands like
@@ -34,11 +43,13 @@
         return text
 
     def plugin_incoming_msg(self, text, type, name, player):
-        text = self.replace(text)
+        if self.toggle.IsChecked() == True:
+            text = self.replace(text)
         return text, type, name
 
     def pre_parse(self, text):
-        text = self.replace(text)
+        if self.toggle.IsChecked() == True:
+            text = self.replace(text)
         return text
 
     def on_spell(self, cmdargs):
--- a/plugins/xxurl2link.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/plugins/xxurl2link.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,6 +1,5 @@
-import os
+import os, re, wx
 import orpg.pluginhandler
-import re
 
 class Plugin(orpg.pluginhandler.PluginHandler):
     # Initialization subroutine.
@@ -19,6 +18,15 @@
         self.url_regex = None
         self.mailto_regex = None
 
+    def plugin_menu(self):
+        self.menu = wx.Menu()
+        self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
+        self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
+        self.toggle.Check(True)
+
+    def plugin_toggle(self, evt):
+        pass
+
     def plugin_enabled(self):
         #This is where you set any variables that need to be initalized when your plugin starts
         self.url_regex = re.compile("(?<![\[=\"a-z0-9:/.])((?:http|ftp|gopher)://)?(?<![@a-z])((?:[a-z0-9\-]+[-.]?[a-z0-9]+)*\.(?:[a-z]{2,4})(?:[a-z0-9_=\?\#\&~\%\.\-/\:\+;]*))", re.I)
@@ -31,13 +39,15 @@
         pass
 
     def pre_parse(self, text):
-        text = self.mailto_regex.sub(self.regmailsub, text)
-        text = self.url_regex.sub(self.regurlsub, text)
+        if self.toggle.IsChecked() == True:
+            text = self.mailto_regex.sub(self.regmailsub, text)
+            text = self.url_regex.sub(self.regurlsub, text)
         return text
 
     def plugin_incoming_msg(self, text, type, name, player):
-        text = self.mailto_regex.sub(self.regmailsub, text)
-        text = self.url_regex.sub(self.regurlsub, text)
+        if self.toggle.IsChecked() == True:
+            text = self.mailto_regex.sub(self.regmailsub, text)
+            text = self.url_regex.sub(self.regurlsub, text)
         return text, type, name
 
     def regmailsub(self, m):
--- a/readme.txt	Fri Jan 15 22:45:51 2010 -0600
+++ b/readme.txt	Sat Apr 24 08:37:20 2010 -0500
@@ -1,9 +1,18 @@
-How to use OpenRPG version 1.7.x
-Make sure you have installed python 2.5+ and wxPython 2.8+!
+Welcome to Traipse 'OpenRPG' Ornery Orc
+Traipse is a fork of the original OpenRPG software. Traipse 
+provides the best stability of any OpenRPG fork, and the best
+features of any OpenRPG version
+
+How to use Traipse 'OpenRPG':
 
-Launching OpenRPG:
-OpenRPG can be launch by executing the OpenRPG.pyw script
-located in the openrpg folder.  On windows, Macs, and
+Minimum software requirements
+* Python 2.5.2
+* wx.Python 2.8.1.9
+
+Launching Traipse 'OpenRPG':
+
+OpenRPG can be launch by executing the Traipse.pyw script
+located in the folder you ran setup.py.  On windows, Macs, and
 Unix with a GUI, this can be accomplished by double
 clicking OpenRPG.pyw. From a shell, type: python OpenRPG.pyw
 
@@ -11,8 +20,8 @@
 You want to launch your own server execute the
 Server.py.
 
-For more info on how to use OpenRPG,
-visit http://www.openrpg.com
+For more info on how to use Traipse 'OpenRPG',
+visit http://www.knowledgearcana.com/traipse-openrpg
 
 
 -OpenRPG Team
--- a/start_noupdate.py	Fri Jan 15 22:45:51 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-
-import pyver
-pyver.checkPyVersion()
-
-#Update Manager
-from orpg.orpg_wx import *
-import upmana.updatemana
-app = upmana.updatemana.updateApp(0)
-app.MainLoop()
-
-#Main Program
-from orpg.orpg_wx import *
-import orpg.main
-
-if WXLOADED:
-    mainapp = orpg.main.orpgApp(0)
-    mainapp.MainLoop()
-else:
-    print "You really really need wx!"
--- a/upmana/updatemana.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/upmana/updatemana.py	Sat Apr 24 08:37:20 2010 -0500
@@ -129,9 +129,7 @@
         ignore.close()
 
     def Finish(self, evt=None):
-        try: component.get('upmana-win').OnClose(None)
-        except Exception, e:
-            print 'Fail', e; exit()
+        component.get('upmana-win').OnClose(None)
 
     def ChooseBranch(self, evt=None):
         dlg = wx.Dialog(self, wx.ID_ANY, "Package Selector", style=wx.DEFAULT_DIALOG_STYLE)
@@ -593,7 +591,7 @@
         ignore.close()
 
     def get_packages(self, type=None):
-        #Fixed and ready for Test. Can be cleaner
+        #Can be cleaner
         self.package_list = []
         b = self.repo.branchtags()
         heads = dict.fromkeys(self.repo.heads(), 1) #The code below looks superfluous but there is good info inside
--- a/upmana/validate.py	Fri Jan 15 22:45:51 2010 -0600
+++ b/upmana/validate.py	Sat Apr 24 08:37:20 2010 -0500
@@ -1,11 +1,3 @@
-# file: config_files.py
-#
-# Author: Todd Faris (Snowdog)
-# Date:   5/10/2005
-#
-# Misc. config file service methods
-#
-
 from orpg.dirpath import dir_struct
 import os