changeset 212:13054be69834 beta

Traipse Beta 'OpenRPG' {100428-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 New Namespace Internal is context sensitive, always! New Namespace External is 'as narrow as you make it' New Namespace FutureCheck helps ensure you don't receive an incorrect node New PluginDB access for URL2Link plugin New to Forms, they now show their content in Design Mode New to Update Manager, checks Repo for updates on software start 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 Fix to Backgrounds not loading through remote loader Fix to Node name errors Fix to rolling dice in chat Whispers Fix to Splitters Sizing issues Fix to URL2Link plugin, modified regex compilation should remove memory leak Fix to mapy.py, a roll back due to zoomed grid issues Fix to whiteboard_handler, Circles work by you clicking the center of the circle Fix to Servers parse_incoming_dom which was outdated and did not respect XML Fix to a broken link in the server welcome message Fix to InterParse and logger requiring traceback Fix to Update Manager Status Bar Fix to failed image and erroneous pop up
author sirebral
date Wed, 28 Apr 2010 08:08:09 -0500
parents 44ef45e77880
children 8b7bb1d72c1c
files orpg/chat/chatwnd.py orpg/chat/commands.py orpg/dieroller/HOWTO.txt orpg/dieroller/base.py orpg/dieroller/dieroller.txt orpg/dieroller/rollers/std.py orpg/gametree/gametree.py orpg/gametree/nodehandlers/chatmacro.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/forms.py orpg/gametree/nodehandlers/rpg_grid.py orpg/main.py orpg/map/__init__.py orpg/map/_background.py orpg/map/_canvas.py orpg/map/_circles.py orpg/map/_fog.py orpg/map/_grid.py orpg/map/_lines.py orpg/map/_minis.py orpg/map/_object.py orpg/map/_text.py orpg/map/_tiles.py orpg/mapper/background.py orpg/mapper/map.py orpg/mapper/whiteboard_handler.py orpg/networking/meta_server_lib.py orpg/networking/mplay_server.py orpg/networking/mplay_server_gui.py orpg/orpg_version.py orpg/templates/default_ignorelist.txt orpg/templates/default_settings.xml orpg/templates/metaservers.cache orpg/templates/nodes/split.xml orpg/templates/nodes/textctrl.xml orpg/tools/InterParse.py orpg/tools/aliaslib.py orpg/tools/orpg_log.py orpg/tools/orpg_settings.py plugins/xxurl2link.py readme.txt rollback.py start_developer.py start_noupdate.py start_tester.py upmana/ignorelist.txt upmana/updatemana.py
diffstat 42 files changed, 842 insertions(+), 2417 deletions(-) [+]
line wrap: on
line diff
--- a/orpg/chat/chatwnd.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/chat/chatwnd.py	Wed Apr 28 08:08:09 2010 -0500
@@ -45,7 +45,7 @@
 ##
 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
@@ -763,9 +763,11 @@
         self.chatwnd = chat_html_window(self,-1)
         self.set_colors()
         wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header())
+        welcome = "<b>Welcome to <a href='http://www.knowledgearcana.com/traipse-openrpg/'>"
+        welcome += DISTRO +'</a> '+ DIS_VER +' {'+BUILD+'},'
+        welcome += ' built on OpenRPG '+ VERSION +'</b>'
         if (self.sendtarget == "all"):
-            wx.CallAfter(self.Post, self.colorize(self.syscolor, 
-                "<b>Welcome to <a href='http://www.openrpg.com'>OpenRPG</a> version " + self.version + "...  </b>"))
+            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 )
@@ -1030,7 +1032,7 @@
         sound_file = self.settings.get_setting("SendSound")
         if sound_file != '': component.get('sound').play(sound_file)
         if s[0] != "/": ## it's not a slash command
-            s = self.ParsePost( s, True, True )
+            s = Parse.Post(s, self, True, True)
         else: self.chat_cmds.docmd(s) # emote is in chatutils.py
 
     def on_chat_key_down(self, event):
@@ -1169,7 +1171,7 @@
         if len(dieMod) and dieMod[0] not in "*/-+": dieMod = "+" + dieMod
         dieText += dieMod
         dieText = "[" + dieText + "]"
-        self.ParsePost(dieText, 1, 1)
+        Parse.Post(dieText, self, 1, 1)
         self.chattxt.SetFocus()
 
     def on_chat_save(self, evt):
@@ -1299,7 +1301,7 @@
         return text
 
     def emote_message(self, text):
-        text = Parse.Normalize(text)
+        text = Parse.Normalize(text, self)
         text = self.colorize(self.emotecolor, text)
         if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE)
         elif self.type == MAIN_TAB and self.sendtarget == "gm":
@@ -1317,7 +1319,7 @@
 
     def whisper_to_players(self, text, player_ids):
         tabbed_whispers_p = self.settings.get_setting("tabbedwhispers")
-        text = Parse.Normalize(text)
+        text = Parse.Normalize(text, self)
         player_names = ""
         for m in player_ids:
             id = m.strip()
@@ -1384,6 +1386,7 @@
         if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name)
         recvSound = "RecvSound"
         # act on the type of messsage
+
         if (type == chat_msg.CHAT_MESSAGE):
             text = "<b>" + display_name + "</b>: " + text
             self.Post(text)
@@ -1589,11 +1592,6 @@
             logger.general("EXCEPTION: " + str(e))
             return "[ERROR]"
 
-    def ParsePost(self, s, send=False, myself=False):
-        s = Parse.Normalize(s)
-        self.set_colors()
-        self.Post(s,send,myself)
-
     # This subroutine builds a chat display name.
     #
     def chat_display_name(self, player):
--- a/orpg/chat/commands.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/chat/commands.py	Wed Apr 28 08:08:09 2010 -0500
@@ -214,14 +214,17 @@
     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()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/HOWTO.txt	Wed Apr 28 08:08:09 2010 -0500
@@ -0,0 +1,72 @@
+HOW TO CREATE A NEW DIE ROLLER
+
+So you want a make a new roller or add a new option? here's a short guide.
+
+
+Step 1:  Create a new die roller sub class.
+
+You need to derive a new die roller class from an existing die roller class.  
+Most likely, this will be the std die roller class. 
+
+The basics would look like this:
+
+class new_roller(std):
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        .....
+
+    ....
+
+Step 2: Implement new methods and/or override existing ones.
+
+Now, you just need to implement any new die options and override any 
+existing ones that you want to act differently.  The most common options 
+to override are the sum and __str__ functions.  Sum is used to determine 
+the result of the rolls and __str__ is used to display the results in 
+a user friendly string.
+
+For example:
+
+class new_roller(std):
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+        .....
+
+    def myoption(self,param):
+        ....
+
+    def sum(self):
+        ....
+
+    def __str__(self):
+        ....
+
+REMEMBER!
+Always return an instance of your die roller for each option expect str and sum.
+
+
+Step 3:
+
+Modify Utils.py
+
+You need to make some minor modifications to utils.py to facilitate 
+your new roller.  You need to a) add an import call for your roller, 
+and b) add your roller to the list of available rollers. 
+
+For example:
+
+from die import *
+# add addtional rollers here
+from myroller import *
+....
+
+rollers = ['std','wod','d20','myroller']
+
+Step 4:  You're done! 
+
+Test it and make sure it works.  When you think its done, send it to 
+the openrpg developers and they might include it in future releases.
+
+-Chris Davis
+
+
--- a/orpg/dieroller/base.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/dieroller/base.py	Wed Apr 28 08:08:09 2010 -0500
@@ -126,7 +126,6 @@
         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)
 
@@ -230,7 +229,7 @@
 ### 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
@@ -264,7 +263,6 @@
     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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/dieroller.txt	Wed Apr 28 08:08:09 2010 -0500
@@ -0,0 +1,309 @@
+The New Dicing System:  A Proposal for OpenRPG
+----------------------------------------------
+
+The current dice system for OpenRPG has several limitations.  Foremost
+among these are the fact that adding a new, non-standard dicing mechanism
+requires editing of the basic dice code.  There are several secondary 
+limitations, such as the fact that while the dice system can handle math,
+it cannot be used as a calculator -- it will not allow expressions that do
+not involve dice.
+
+This proposal is for a new dicing system to replace the current one in
+OpenRPG.  Since the dicing system is something that users will interact
+with frequently, a new system needs to be considered carefully.  This
+document attempts to describe the new dicing system so that such 
+consideration can be given to it.  It is expected that this document will
+grow and change as it is scrutinized.
+
+
+Design goals for this dicing system:
+
+ 1. Should be easy for new users to get started with, based on knowing
+    standard RPG dice notation (NdX) and basic math.
+
+ 2. Should, as far as practical, maintain compatibility with existing
+    character sheets, etc., that use the current dice system.
+
+ 3. Should allow users to create new dice types and new ways of 
+    counting dice.  Ideally, this should not require programming, except
+    in exceptional cases.
+
+ 4. The dice system should be usable for doing basic math that does
+    not involve dice.
+
+ 5. The dice system should be able to handle most current RPG dicing
+    systems.
+
+Things this dicing system is designed to NOT do:
+
+ 1. Be a programming language.  There are no facilities in it for 
+    user input, output formatting, loops, if-then-else, or similar
+    things.  If these are desired for something involving dice, an
+    appropriate node and nodehandler can be created.
+
+ 2. Handle all theoretically possible dicing systems without the
+    need for programming plugins.  First off, this is impossible.  
+    Second, even making an attempt to would require supporting 
+    dicing methods that don't actually turn up in any real game.
+
+ 3. Handle floating-point math.  I don't know of any systems that
+    use it in their dice schemes right now.  If there are some,
+    we might have to consider adding it.
+
+
+Syntax Specification 
+
+What follows is a BNF specification for the proposed dicing system, with
+explanatory text interleaved.  At the end of this document is a copy of
+the BNF with no explanations, for those who would like to look at it "all
+together".  Note that BNF describes only syntax, and not semantics; thus,
+while anything generated with this grammar should be syntactically correct,
+that doesn't mean it will make sense or be allowed.
+
+
+dice string ::= <expression>
+                <expression> of <comparison> | <comparison>
+
+This is the top level.  The major thing of note here is that comparisons
+only occur at this level.  This is intentional; the result of a comparison
+is a boolean true/false flag rather than a number.  Thus, it makes no 
+sense to allow people to perform further numerical operations on the 
+result of a comparison.  Systems where dice are triggered by the results 
+of other dice are left for the realm of plugins.
+
+                
+comparison ::= <expression> <relation> <expression>
+
+expression ::= <factor> | <factor> <low-op> <factor>
+
+The separation into "low-op" and "high-op" of the operators is to allow
+order of operations to be handled more easily.  Syntactically, it's not
+really necessary, but it should be helpful in implementation.
+
+
+factor :: = <term> | <term> <high-op> <term> |
+            <multi-dice> | <multi-dice> <high-op> <term> |
+            <term> <high-op> <multi-dice>
+
+Here we start to hit some complication.  The intent of the different 
+entries for multi-dice is that we don't want to allow things like
+[3d6 each * 2d6 each].  We are *not* doing vector multiplication!
+The "expression" level doesn't have any such limitation on syntax; 
+things like [3d6 each + 2d6 each] we'll have to either think of a 
+logical way to handle, or disallow on a semantic level.  (Well... I 
+suppose it could be handled in the BNF, but I think it would get
+kind of messy.)
+
+
+term ::= <dice> | <unit>
+
+unit ::= <number> | ( <expression> )
+
+Dice are not considered a unit.  This means that things like [3d6d10] can't
+be done without using parentheses.  I consider that to be a win for 
+clarity.
+
+
+dice ::= <unit>d<unit> | <unit>d<name> | <dice> <flag> | lastroll
+
+The <name> entry here allows for user-created dice (in the syntax, at 
+least...).
+
+
+multi-dice ::= ( <dice>, <dice>+ ) |               # (1d6,1d8)
+               <dice> each |                       # 3d6 each
+               ( <expression> of <expression> ) |  # (3 of 2d6)
+               lastroll |                          # lastroll
+               <multi-dice> <flag>                 # (3 of 2d6) best 2
+
+"lastroll" by itself can be either dice or multi-dice.  I'm thinking that it
+ 
+should be whatever type the last roll was.
+
+
+flag ::= reroll <condition> |          # repeats
+         reroll <slice> |              # once only
+         grow <condition> |            # reroll and add
+         shrink <condition> |          # reroll and subtract
+         drop <condition> |
+         drop <slice> |
+         take <condition> |
+         take <slice> |
+         <slice> |                     # implied "take"
+         <name> <condition> |          # user-created
+         <name>                        # user-created
+
+Technically, we don't need both "drop" and "take" -- one implies the 
+other.  However, having both should make the language easier to use.
+
+"reroll" will work differently depending on whether a condition or a 
+slice is given.  If a condition is given, it will reroll until none of
+the dice in the set meet the reroll condition (or until it hits a maximum
+allowed number of rerolls).  If a slice is given, it will reroll those
+dice once.  IMHO, this behavior makes the most sense.
+
+The <name> entries here are to allow for user-created flags.  Note that
+as I've specified things right now, a user-created flag can have a
+ condition,
+but not a slice.  That's mostly because I couldn't think of a case where
+a slice would be useful... should we add it anyways?
+
+
+slice ::= highest | lowest | highest <number> | lowest <number>
+
+"highest" and "lowest" without a number are equivalent to doing them with
+1 as the number.  This is to simplify things like [4d6 drop lowest].
+
+
+condition ::= <relation> <unit>
+
+This is for conditions on flags.  Note that it can take a unit, so you could
+
+use dice in a condition; however, I think the unit should only be evaluated 
+
+once, to make things faster.  Anyone for repetitive evaluation?
+
+
+low-op ::= + | - | min | max
+
+"min" takes two values and returns the highest of them, and "max"
+returns the lowest of them.  This might seem counterintuitive, but
+it's meant to be used with dice, like so:
+
+  3d6 min 8   - always returns 8 or higher
+
+  3d6 max 15  - always returns 15 or lower
+
+I decided to put min and max as having the same precedence as + and -,
+because if they had higher precedence, then:
+
+  3d6+2 min 10 
+
+would be equivalent to 3d6+10.  (It would take the max of 2 and 10, then
+add that to 3d6).  One problem that does arise here is with multiplication 
+and division:  [1d6 min 5 * 2] will be equivalent to [1d6 min 10], since
+multiplication has higher precedence.  We may just want to warn people 
+that min and max can be screwy unless you parenthesize, unless someone can
+think of a better way to handle them.
+
+
+high-op ::= * | / | mod
+
+The / is integer division, of course, since we're doing integer math.  
+
+
+number ::= <digit>+ | -<digit>+
+
+Positive and negative numbers are allowed.  This means that, syntactically,
+[-2d-4] is legal.  Do we want to modify the BNF to disallow this, or handle
+it on a semantic level?
+
+
+name ::= <letter>[<letter>|<digit>]*
+
+We may want to expand to allow underscores and dashes in user-created names.
+
+
+
+letter ::= A-Z | a-z
+
+digit ::= 0-9
+
+relation ::= < | > | <= | >= | => | =< | = | ==
+
+
+
+Well, that's the BNF.  Again, at the end is a copy without all the running
+commentary.
+
+
+Thoughts on Implementation:
+
+First, I think a sort of "dice library" of common functions needs to be
+created.  This would include rolling a set of dice, getting the highest
+of a group of dice, growing and shrinking dice from a set based on 
+conditions, and so on.  These functions should be available for use by
+custom-written dice types.
+
+Next, that library should be used as a tool in implementing a dice-string
+interpreter.  That will require creating a parser for the dice-string 
+'language'.  This could be either a custom-written parser, or possibly
+one created with some of the Python parser generators.  A custom-written
+parser may take longer to do and be a bit more finicky to maintain, but
+it would remove a dependency from the code.
+
+User-created flags and dice types could be supported in two ways:
+
+ - First, by allowing users to specify strings in the dice language
+   that the flags/expressions would expand to -- basically, allowing
+   dice macros.
+
+ - Second, by adding hooks for python modules to be associated with
+   user-created dice or flag types.  This is likely to be the more
+   complicated of the two solutions, but it would also be more 
+   flexible.
+
+Personally, I think both are desirable -- the first, so that 
+non-programming users can create simple die and flag types.  The
+second, because by design, there are some things this dice system 
+just won't do.
+
+
+Further work needed:
+
+ - specs for the "dice library"
+
+ - specs on an interface for python modules meant to be dice and
+   flag types.
+
+----------------------------------------------------------------
+
+start ::= <expression> |
+          <comparison>
+
+comparison ::= <expression> <condition>
+
+expression ::= <term> | <term> <low-op> <factor>
+
+term ::= <factor> | <factor> <high-op> <unit>
+
+factor ::= <atom> | <dice_set>
+
+atom ::= <number> | ( <expression> )
+
+dice_set ::= <dice> <dice_set>, <dice> | <expr> of <dice> | <dice> each |
+             lastroll
+
+dice ::= <atom>d<atom> | <atom>d<name> | <dice> <flag>
+
+flag ::= reroll <condition> |
+         reroll <slice> |
+         grow <condition> |  
+         shrink <condition> |        
+         drop <condition> |
+         drop <slice> |
+         take <condition> |
+         take <slice> |
+         <slice> |         
+         <name> <condition> |
+	 <name> <slice> |
+         <name>
+
+slice ::= highest | lowest | highest <number> | lowest <number>
+
+condition ::= <relation> <unit>
+
+low-op ::= + | -
+
+high-op ::= * | / | mod| max | min
+
+number ::= <digit>+ | -<digit>+
+
+name ::= <letter>[<letter>|<digit>]*
+
+letter ::= A-Z | a-z
+
+digit ::= 0-9
+
+relation ::= < | > | <= | >= | => | =< | = | ==
+
--- a/orpg/dieroller/rollers/std.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/dieroller/rollers/std.py	Wed Apr 28 08:08:09 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)
--- a/orpg/gametree/gametree.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/gametree/gametree.py	Wed Apr 28 08:08:09 2010 -0500
@@ -21,11 +21,18 @@
 # Author: Chris Davis
 # Maintainer:
 # Version:
-#   $Id: gametree.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
+#   $Id: gametree.py,v 1.68 2007/12/07 20:39:48 digitalxero Exp $
 #
 # Description: The file contains code fore the game tree shell
 #
-# Traipse EZ_Tree Reference System (TaS - Prof.Ebral): v Traipse 'Ornery-Orc' prof.ebral Exp
+# Traipse EZ_Tree Reference System (TaS - Prof.Ebral):
+#
+# The new EZ_Tree Reference System being implemented takes full advantage of 
+# Python's OOP Language. The entire tree code is being reused, but a new ID is 
+# being created which 'shuts off' some of the features of the tree and adds new ones.
+# This new feature will allow users to quickly add a Reference button to new node
+# handlers. The button will show a faximile of the tree and users can then create a
+# node reference with ease!
 #
 
 from __future__ import with_statement
@@ -37,7 +44,7 @@
 from orpg.orpgCore import component
 from orpg.dirpath import dir_struct
 from nodehandlers import core
-import string, urllib, time, os, shutil
+import string, urllib, time, os
 
 from orpg.orpg_xml import xml
 from orpg.tools.validate import validate
@@ -82,12 +89,6 @@
 TOP_FEATURES = wx.NewId()
 EZ_REF = wx.NewId()
 
-def exists(path):
-    try:
-        os.stat(path)
-        return True
-    except: return False
-
 class game_tree(wx.TreeCtrl):
     
     def __init__(self, parent, id):
@@ -239,14 +240,11 @@
             self.xml_root = None
 
         if not self.xml_root:
-            count = 1
-            while exists(filename[:len(filename)-4]+'-bad-'+str(count)+'.xml'): count += 1
-            shutil.copy(filename, filename[:len(filename)-4]+'-bad-'+str(count)+'.xml')
-            shutil.copyfile(dir_struct["template"]+'default_tree.xml', filename)
+            os.rename(filename,filename+".corrupt")
             emsg = "Your gametree is being regenerated.\n\n"\
                  "To salvage a recent version of your gametree\n"\
                  "exit OpenRPG and copy the lastgood.xml file in\n"\
-                 "your myfiles directory to "+filename[:len(filename)-4]+'-bad-'+str(count)+'.xml'+ "\n"\
+                 "your myfiles directory to "+filename+ "\n"\
                  "in your myfiles directory.\n\n"\
                  "lastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.\n\n"\
                  "Would you like to select a different gametree file to use?\n"\
@@ -288,11 +286,8 @@
 
         except Exception, e:
             logger.exception(traceback.format_exc())
-            count = 1
-            while exists(filename[:len(filename)-4]+'-bad-'+str(count)+'.xml'): count += 1
-            shutil.copy(filename, filename[:len(filename)-4]+'-bad-'+str(count)+'.xml')
-            shutil.copyfile(dir_struct["template"]+'default_tree.xml', filename)
             wx.MessageBox("Corrupt Tree!\nYour game tree is being regenerated. To\nsalvage a recent version of your gametree\nexit OpenRPG and copy the lastgood.xml\nfile in your myfiles directory\nto "+filename+ "\nin your myfiles directory.\nlastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.")
+            os.rename(filename,filename+".corrupt")
             validate.config_file("tree.xml","default_tree.xml")
             self.load_tree(error=1)
     
@@ -809,7 +804,7 @@
         self.rename_flag = 0
         if txt != "":
             obj = self.GetPyData(item)
-            obj.xml_root.setAttribute('name',txt)
+            obj.xml_root.set('name',txt)
         else: evt.Veto()
     
     def on_label_begin(self, evt):
--- a/orpg/gametree/nodehandlers/chatmacro.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/gametree/nodehandlers/chatmacro.py	Wed Apr 28 08:08:09 2010 -0500
@@ -98,6 +98,6 @@
         txt = self.text[id].GetValue()
         if txt == "": return
         if id == P_TITLE:
-            self.handler.xml.setAttribute('name',txt)
+            self.handler.xml.set('name',txt)
             self.handler.rename(txt)
         elif id == P_BODY: self.handler.set_text(txt)
--- a/orpg/gametree/nodehandlers/containers.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/gametree/nodehandlers/containers.py	Wed Apr 28 08:08:09 2010 -0500
@@ -245,7 +245,6 @@
         parent.SetSize(self.GetBestSize())
         self.Bind(wx.EVT_TEXT, self.on_text, id=1)
 
-
     def on_text(self,evt):
         txt = self.title.GetValue()
         if txt != "":
@@ -281,19 +280,19 @@
         container_handler.on_drop(self,evt)
 
     def build_splitter_wnd(self, parent, mode):
+        self.parent = parent
         self.split = self.xml.get("horizontal")
-        self.pane = splitter_panel(parent, self)
+        self.pane = splitter_panel(parent, self, mode)
+        self.frame = self.pane.frame
         self.splitter = MultiSplitterWindow(self.pane, -1, 
                         style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH|wx.SP_NO_XP_THEME)
+        self.splitter.parent = self
         if self.split == '1': self.splitter.SetOrientation(wx.VERTICAL)
         else: self.splitter.SetOrientation(wx.HORIZONTAL)
-        self.bestSizex = -1
-        self.bestSizey = -1
         self.tree.traverse(self.mytree_node, self.doSplit, mode, False) 
-        self.pane.sizer.Add(self.splitter, 1, wx.EXPAND)
-        if mode != 1: self.pane.hozCheck.Hide()
-        self.pane.SetSize((self.bestSizex, self.bestSizey))
-        self.pane.Layout()
+        self.pane.sizer.Add(self.splitter, -1, wx.EXPAND)
+        self.pane.SetAutoLayout(True)
+        self.pane.Fit()
         parent.SetSize(self.pane.GetSize())
         return self.pane
 
@@ -301,41 +300,40 @@
         node = self.tree.GetPyData(treenode)
         if mode == 1: tmp = node.get_design_panel(self.splitter)
         else: tmp = node.get_use_panel(self.splitter)
-        if self.split == '1':
-            sash = tmp.GetBestSize()[1]+1
-            self.bestSizey += sash+11
-            if self.bestSizex < tmp.GetBestSize()[0]: self.bestSizex = tmp.GetBestSize()[0]+10
-        else:
-            sash = tmp.GetBestSize()[0]+1
-            self.bestSizex += sash
-            if self.bestSizey < tmp.GetBestSize()[1]: self.bestSizey = tmp.GetBestSize()[1]+31
+        if self.split == '1': sash = self.frame.GetSize()[1]/len(self.xml.findall('nodehandler'))
+        else: sash = self.frame.GetSize()[0]/len(self.xml.findall('nodehandler'))
         self.splitter.AppendWindow(tmp, sash)
+
     def get_size_constraint(self):
         return 1
 
 class splitter_panel(wx.Panel):
-    def __init__(self, parent, handler):
+    def __init__(self, parent, handler, mode):
         wx.Panel.__init__(self, parent, -1)
+        self.parent = parent
         self.handler = handler
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
-
-        self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
-        hoz = self.handler.xml.get("horizontal")
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        if mode == 0: self.title = wx.StaticText(self, 1, handler.xml.get('name'))
+        elif mode == 1: self.title = wx.TextCtrl(self, 1, handler.xml.get('name'))
+        self.frame = self.GetParent()
+        while self.frame.GetName() != 'frame':
+            self.frame = self.frame.GetParent()
 
-        if hoz == '1': self.hozCheck.SetValue(True)
-        else: self.hozCheck.SetValue(False)
+        if mode == 1:
+            self.hozCheck = wx.CheckBox(self, -1, "Horizontal Split")
+            hoz = self.handler.xml.get("horizontal")
+            if hoz == '1': self.hozCheck.SetValue(True)
+            else: self.hozCheck.SetValue(False)
 
-        sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
-        sizer.Add(self.title, 0)
-        sizer.Add(self.hozCheck, 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,0))
+        if mode == 1: self.sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.sizer.Add(self.title, 0)
+        if mode == 1: self.sizer.Add(self.hozCheck, 0, wx.EXPAND)
+        self.sizer.Add(wx.Size(10,0))
 
-        self.sizer = sizer
         self.SetSizer(self.sizer)
         self.SetAutoLayout(True)
         self.Bind(wx.EVT_TEXT, self.on_text, id=1)
-        self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
+        if mode == 1: self.Bind(wx.EVT_CHECKBOX, self.on_check_box, id=self.hozCheck.GetId())
 
     def on_check_box(self,evt):
         state = self.hozCheck.GetValue()
--- a/orpg/gametree/nodehandlers/forms.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/gametree/nodehandlers/forms.py	Wed Apr 28 08:08:09 2010 -0500
@@ -109,11 +109,11 @@
 
 F_HEIGHT = wx.NewId()
 F_WIDTH = wx.NewId()
-class form_edit_panel(wx.Panel):
+class form_edit_panel(ScrolledPanel):
     def __init__(self, parent, handler):
-        wx.Panel.__init__(self, parent, -1)
+        ScrolledPanel.__init__(self, parent, wx.ID_ANY, style=wx.NO_BORDER|wx.VSCROLL|wx.HSCROLL)
         self.handler = handler
-        sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Form Properties"), wx.VERTICAL)
+        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
         wh_sizer = wx.BoxSizer(wx.HORIZONTAL)
         self.text = {   P_TITLE : wx.TextCtrl(self, P_TITLE, handler.xml.get('name')),
                         F_HEIGHT : wx.TextCtrl(self, F_HEIGHT, handler.xml.get('height')),
@@ -128,15 +128,17 @@
         wh_sizer.Add(wx.Size(10,10))
         wh_sizer.Add(self.text[F_HEIGHT], 0, wx.EXPAND)
 
-        sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
-        sizer.Add(self.text[P_TITLE], 0, wx.EXPAND)
-        sizer.Add(wx.Size(10,10))
-        sizer.Add(wh_sizer,0,wx.EXPAND)
+        self.main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
+        self.main_sizer.Add(self.text[P_TITLE], 0, wx.EXPAND)
+        self.main_sizer.Add(wx.Size(10,10))
+        self.main_sizer.Add(wh_sizer,0,wx.EXPAND)
+        handler.tree.traverse(handler.mytree_node, self.create_child_wnd, None, False)
 
-        self.SetSizer(sizer)
+        self.SetSizer(self.main_sizer)
         self.SetAutoLayout(True)
+        self.SetupScrolling()
+        parent.SetSize(self.GetSize())
         self.Fit()
-        parent.SetSize(self.GetBestSize())
 
         self.Bind(wx.EVT_TEXT, self.on_text, id=P_TITLE)
         self.Bind(wx.EVT_TEXT, self.on_text, id=F_HEIGHT)
@@ -155,6 +157,14 @@
             if id == F_HEIGHT: self.handler.xml.set("height",txt)
             elif id == F_WIDTH: self.handler.xml.set("width",txt)
 
+    def create_child_wnd(self, treenode, evt):
+        node = self.handler.tree.GetPyData(treenode)
+        panel = node.get_design_panel(self)
+        size = node.get_size_constraint()
+        if panel:
+            self.main_sizer.Add(panel, size, wx.EXPAND)
+            self.main_sizer.Add(wx.Size(10,10))
+
 ##########################
 ## control handler
 ##########################
@@ -263,16 +273,16 @@
 
     def on_send(self, evt):
         txt = self.text.GetValue()
-        txt = Parse.NodeMap(txt, self.handler.xml)
-        txt = Parse.NodeParent(txt, self.handler.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.handler.xml)
         if not self.handler.is_raw_send():
-            Parse.Post(self.handler.tohtml(), True, True)
+            Parse.Post(self.handler.tohtml(), self.chat, True, True)
             return 1
         actionlist = txt.split("\n")
         for line in actionlist:
+            line = Parse.ParseLogic(line, self.handler.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    Parse.Post(line, True, True)
+                    Parse.Post(line, self.chat, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -320,7 +330,7 @@
             sizer_style=wx.EXPAND
             text_style = 0
             multi = 0
-        self.text = wx.TextCtrl(self, F_TEXT, handler.get_value(),style=text_style)
+        self.text = wx.TextCtrl(self, F_TEXT, handler.get_value() or '',style=text_style)
         sizer.Add(wx.Size(5,0))
         sizer.Add(self.text, multi, sizer_style)
         self.SetSizer(sizer)
@@ -596,18 +606,16 @@
 
     def on_send_to_chat(self, evt):
         txt = self.get_selected_text()
-        txt = Parse.NodeMap(txt, self.xml)
-        txt = Parse.NodeParent(txt, self.xml.get('map'))
+        txt = Parse.ParseLogic(txt, self.xml)
         if not self.is_raw_send():
-            Parse.Post(self.tohtml(), True, True)
+            Parse.Post(self.tohtml(), self.chat, True, True)
             return 1
         actionlist = self.get_selections_text()
         for line in actionlist:
-            line = Parse.NodeMap(line, self.xml)
-            line = Parse.NodeParent(line, self.xml.get('map'))
+            line = Parse.ParseLogic(line, self.xml)
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
-                    Parse.Post(line, True, True)
+                    Parse.Post(line, self.chat, True, True)
                 else:
                     action = line
                     self.chat.chat_cmds.docmd(action)
@@ -621,6 +629,7 @@
 class listbox_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
+        #ScrolledPanel.__init__(self, parent, wx.ID_ANY, style=wx.NO_BORDER|wx.VSCROLL|wx.HSCROLL)
         self.handler = handler
         self.chat = handler.chat
         opts = []
@@ -638,8 +647,8 @@
             if self.list.GetSize()[0] > 200:
                 self.list.Destroy()
                 self.list = wx.ComboBox(self, F_LIST, cur_opt, size=(200, -1), choices=opts, style=wx.CB_READONLY)
-        elif type == L_LIST: self.list = wx.ListBox(self,F_LIST,choices=opts)
-        elif type == L_RADIO: self.list = wx.RadioBox(self,F_LIST,label,choices=opts,majorDimension=3)
+        elif type == L_LIST: self.list = wx.ListBox(self, F_LIST, choices=opts)
+        elif type == L_RADIO: self.list = wx.RadioBox(self, F_LIST, label, choices=opts, majorDimension=3)
         elif type == L_CHECK:
             self.list = wx.CheckListBox(self,F_LIST,choices=opts)
             self.set_checks()
@@ -651,17 +660,17 @@
         else: sizer = wx.BoxSizer(wx.VERTICAL)
 
         if type != L_RADIO:
-            sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
-            sizer.Add(wx.Size(5,0))
-        sizer.Add(self.list, 1, wx.EXPAND)
+            sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND|wx.ALL)
+        sizer.Add(self.list, 1, wx.EXPAND|wx.ALL)
         if handler.has_send_button():
-            sizer.Add(wx.Button(self, F_SEND, "Send"), 0, wx.EXPAND)
+            sizer.Add(wx.Button(self, F_SEND, "Send"), 0, wx.EXPAND|wx.ALL)
             self.Bind(wx.EVT_BUTTON, self.handler.on_send_to_chat, id=F_SEND)
         self.sizer = sizer
         self.SetSizer(sizer)
         self.SetAutoLayout(True)
+        #self.SetupScrolling()
+        #parent.SetSize(self.GetBestSize())
         self.Fit()
-        parent.SetSize(self.GetBestSize())
 
         if type == L_DROP: self.Bind(wx.EVT_COMBOBOX, self.on_change, id=F_LIST)
         elif type == L_LIST: self.Bind(wx.EVT_LISTBOX, self.on_change, id=F_LIST)
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Wed Apr 28 08:08:09 2010 -0500
@@ -89,7 +89,7 @@
                 html_str += "<td >"
                 text = c.text
                 if text == None or text == '': text = '<br />'
-                s = Parse.NodeMap(text, self.xml)
+                s = Parse.ParseLogic(text, self.xml)
                 s = Parse.Normalize(s)
                 try: text = str(eval(s))
                 except: text = s
@@ -327,8 +327,7 @@
                 text = ''
                 cells[i].text = text
             if self.mode == 0:
-                s = Parse.NodeMap(text, self.handler.xml)
-                s = Parse.NodeParent(s, self.handler.xml.get('map'))
+                s = Parse.ParseLogic(text, self.handler.xml)
                 try: text = str(eval(s))
                 except: text = s
             self.SetCellValue(rowi,i,text)
--- a/orpg/main.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/main.py	Wed Apr 28 08:08:09 2010 -0500
@@ -622,7 +622,7 @@
         # Update Manager 
         #self.manifest = manifest.ManifestChanges()
         self.updateMana = upmana.updatemana.updaterFrame(self, 
-            "OpenRPG Update Manager 1.0", component, manifest, True)
+            "OpenRPG Update Manager 1.2", component, manifest, True)
         component.add('upmana-win', self.updateMana)
         logger.debug("Menu Created")
         h = int(xml_dom.get("height"))
@@ -790,7 +790,7 @@
             temp_wnd = orpg.chat.chatwnd.chat_notebook(parent_wnd, wx.DefaultSize)
             self.chattabs = temp_wnd
             self.chat = temp_wnd.MainChatPanel
-            component.add("chat",self.chat)
+            component.add("chat", self.chat)
 
         elif name == "player":
             temp_wnd = orpg.player_list.player_list(parent_wnd)
--- a/orpg/map/__init__.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-from threading import Lock
-import mimetypes
-import xml.dom.minidom as minidom
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-from orpg.tools.rgbhex import RGBHex
-import orpg.tools.ButtonPanel as BP
-
-from _canvas import MapCanvas
-
-class MapWnd(wx.Panel):
-    def __init__(self, parent, openrpg):
-        wx.Panel.__init__(self, parent, wx.ID_ANY)
-        self.openrpg = openrpg
-        self.log = self.openrpg.get_component("log")
-        self.xml = self.openrpg.get_component("xml")
-        self.dir_struct = self.openrpg.get_component("dir_struct")
-        self.validate = self.openrpg.get_component("validate")
-        self.settings = self.openrpg.get_component("settings")
-
-        self.Freeze()
-        sizer = wx.GridBagSizer(hgap=1, vgap=1)
-        sizer.SetEmptyCellSize((0,0))
-
-        self.canvas = MapCanvas(self, self.openrpg)
-        sizer.Add(self.canvas, (0,0), flag=wx.EXPAND)
-
-        self.gmToolBar = BP.ButtonPanel(self, wx.ID_ANY)
-        sizer.Add(self.gmToolBar, (1,0), flag=wx.EXPAND)
-        self.playerToolBar = BP.ButtonPanel(self, wx.ID_ANY)
-        sizer.Add(self.playerToolBar, (2,0), flag=wx.EXPAND)
-
-        sizer.AddGrowableCol(0)
-        sizer.AddGrowableRow(0)
-
-        self.SetSizer(sizer)
-        self.SetAutoLayout(True)
-
-        self._CreateToolBar()
-
-        self.Bind(wx.EVT_MOUSEWHEEL, self.canvas.OnZoom)
-        self.Bind(wx.EVT_KEY_DOWN, self.canvas.OnKey)
-        self.Bind(wx.EVT_KEY_UP, self.canvas.OnKey)
-        self.Layout()
-        self.Thaw()
-
-        wx.CallAfter(self.PostLoad)
-
-    #Public API
-    def PostLoad(self):
-        self.canvas.Clear()
-        #self.canvas.roleTimer.Start(100)
-        self.canvas.UpdateMap()
-
-    #Events
-
-
-    #Private Methods
-    def _SetColorBtn(self, color, btn):
-        dc = wx.MemoryDC()
-        bmp = wx.EmptyBitmap(16, 16)
-        dc.SelectObject(bmp)
-        dc.SetBrush(wx.Brush(color))
-        dc.DrawRectangle(0,0, 16, 16)
-
-        del dc
-
-        btn.SetBitmap(bmp)
-
-    def _CreateToolBar(self):
-        self.exclusiveToolList = {}
-
-        self.OpenBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'open.bmp', wx.BITMAP_TYPE_BMP), kind=wx.ITEM_NORMAL, shortHelp="Load New Map", longHelp="Load New Map")
-        self.gmToolBar.AddButton(self.OpenBtn)
-
-        self.SaveBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'save.bmp', wx.BITMAP_TYPE_BMP), kind=wx.ITEM_NORMAL, shortHelp="Save Map", longHelp="Save Map")
-        self.gmToolBar.AddButton(self.SaveBtn)
-
-        self.DefaultBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'defaultmap.png', wx.BITMAP_TYPE_PNG), kind=wx.ITEM_NORMAL, shortHelp="Load Default Map", longHelp="Load Default Map")
-        self.gmToolBar.AddButton(self.DefaultBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnDefaultBtn, id=self.DefaultBtn.GetId())
-
-        self.MapPropsBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'compass.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Map Properties", longHelp="Map Properties")
-        self.gmToolBar.AddButton(self.MapPropsBtn)
-
-
-        self.gmToolBar.AddSeparator()
-
-        self.BGBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'img.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Change Background", longHelp="Change Background")
-        self.gmToolBar.AddButton(self.BGBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnBGBtn, id=self.BGBtn.GetId())
-
-        self.BGColorBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.EmptyBitmap(16,16), kind=wx.ITEM_NORMAL, shortHelp="Map Background Color", longHelp="Map Background Color")
-        self.gmToolBar.AddButton(self.BGColorBtn)
-        self._SetColorBtn(wx.GREEN, self.BGColorBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnBGColorBtn, id=self.BGColorBtn.GetId())
-
-        self.TileAddBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'chess.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Add Map Tile", longHelp="Add Map Tile")
-        self.gmToolBar.AddButton(self.TileAddBtn)
-
-        self.TileMoveBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'crosshair.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_CHECK, shortHelp="Edit Tiles", longHelp="Edit Tiles")
-        self.gmToolBar.AddButton(self.TileMoveBtn)
-        self.exclusiveToolList[self.TileMoveBtn.GetId()] = self.TileMoveBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.TileMoveBtn.GetId())
-
-        self.GridBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'grid.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Set Grid", longHelp="Set Grid")
-        self.gmToolBar.AddButton(self.GridBtn)
-
-        self.gmToolBar.AddSeparator()
-
-        self.FogBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'fogon.png', wx.BITMAP_TYPE_PNG), kind=wx.ITEM_CHECK, shortHelp="Turn Fog On", longHelp="Turn Fog On")
-        self.gmToolBar.AddButton(self.FogBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnFogBtn, id=self.FogBtn.GetId())
-
-        self.FogToolBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'showfog.png', wx.BITMAP_TYPE_PNG), kind=wx.ITEM_CHECK, shortHelp="Show Tool", longHelp="Show Tool")
-        self.gmToolBar.AddButton(self.FogToolBtn)
-        self.exclusiveToolList[self.FogToolBtn.GetId()] = self.FogToolBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.FogToolBtn.GetId())
-        menu = wx.Menu("Fog Tool")
-        item = wx.MenuItem(menu, 1, "Show", "Show")
-        self.Bind(wx.EVT_MENU, self.OnFogSelection, item)
-        menu.AppendItem(item)
-        item = wx.MenuItem(menu, 2, "Hide", "Hide")
-        self.Bind(wx.EVT_MENU, self.OnFogSelection, item)
-        menu.AppendItem(item)
-        self.currentFog = 'Show'
-        self.FogToolBtn.SetMenu(menu)
-
-        self.FogColorBtn = BP.ButtonInfo(self.gmToolBar, wx.ID_ANY, wx.EmptyBitmap(16,16), kind=wx.ITEM_NORMAL, shortHelp="Fog Color", longHelp="Fog Color")
-        self.gmToolBar.AddButton(self.FogColorBtn)
-        self._SetColorBtn(wx.BLACK, self.FogColorBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnFogColorBtn, id=self.FogColorBtn.GetId())
-
-        self.gmToolBar.AddSeparator()
-
-        self.MiniPropsBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'questionhead.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Miniture Properties", longHelp="Miniture Properties")
-        self.gmToolBar.AddButton(self.MiniPropsBtn)
-
-        self.gmToolBar.DoLayout()
-
-        self.SelectorBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'mouse.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_CHECK, shortHelp="Selection Tool", longHelp="Selection Tool")
-        self.playerToolBar.AddButton(self.SelectorBtn)
-        self.exclusiveToolList[self.SelectorBtn.GetId()] = self.SelectorBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.SelectorBtn.GetId())
-
-        self.MeasureBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'tape.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_CHECK, shortHelp="Measure Tool", longHelp="Measure Tool")
-        self.playerToolBar.AddButton(self.MeasureBtn)
-        self.exclusiveToolList[self.MeasureBtn.GetId()] = self.MeasureBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.MeasureBtn.GetId())
-
-        self.ColorBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.EmptyBitmap(16,16), kind=wx.ITEM_NORMAL, shortHelp="Select a Color", longHelp="Select a Color")
-        self.playerToolBar.AddButton(self.ColorBtn)
-        self._SetColorBtn(wx.BLACK, self.ColorBtn)
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnColorBtn, id=self.ColorBtn.GetId())
-
-        self.DrawBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'draw.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_CHECK, shortHelp="Freehand Line Tool", longHelp="Freehand Line Tool")
-        self.playerToolBar.AddButton(self.DrawBtn)
-        self.exclusiveToolList[self.DrawBtn.GetId()] = self.DrawBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.DrawBtn.GetId())
-        menu = wx.Menu("Line Tool")
-        item = wx.MenuItem(menu, 3, "Free Draw", "Free Draw")
-        self.Bind(wx.EVT_MENU, self.OnLineSelection, item)
-        menu.AppendItem(item)
-        item = wx.MenuItem(menu, 4, "Poly Draw", "Poly Draw")
-        self.Bind(wx.EVT_MENU, self.OnLineSelection, item)
-        menu.AppendItem(item)
-        self.currentLine = 'Free'
-        self.DrawBtn.SetMenu(menu)
-
-        self.AddTextBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'text.png', wx.BITMAP_TYPE_PNG), kind=wx.ITEM_CHECK, shortHelp="Add Text Tool", longHelp="Add Text Tool")
-        self.playerToolBar.AddButton(self.AddTextBtn)
-        self.exclusiveToolList[self.AddTextBtn.GetId()] = self.AddTextBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.AddTextBtn.GetId())
-
-        self.AddShapeBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'circle.png', wx.BITMAP_TYPE_PNG), kind=wx.ITEM_CHECK, shortHelp="Add Shape Tool", longHelp="Add Shape Tool")
-        self.playerToolBar.AddButton(self.AddShapeBtn)
-        self.exclusiveToolList[self.AddShapeBtn.GetId()] = self.AddShapeBtn
-        self.Bind(wx.EVT_BUTTON, self.canvas.OnExlusiveBtn, id=self.AddShapeBtn.GetId())
-        menu = wx.Menu("Shape Tool")
-        item = wx.MenuItem(menu, 5, "Circle", "Circle")
-        self.Bind(wx.EVT_MENU, self.OnShapeSelection, item)
-        menu.AppendItem(item)
-        item = wx.MenuItem(menu, 6, "Rectangle", "Rectangle")
-        self.Bind(wx.EVT_MENU, self.OnShapeSelection, item)
-        menu.AppendItem(item)
-        item = wx.MenuItem(menu, 7, "Arc", "Arc")
-        self.Bind(wx.EVT_MENU, self.OnShapeSelection, item)
-        menu.AppendItem(item)
-        self.currentShape = 'Circle'
-        self.AddShapeBtn.SetMenu(menu)
-
-        self.LineWidth = wx.Choice(self.playerToolBar, wx.ID_ANY, choices=["1","2","3","4","5","6","7","8","9","10"])
-        self.LineWidth.SetSelection(0)
-        self.playerToolBar.AddControl(self.LineWidth)
-
-        self.playerToolBar.AddSeparator()
-
-        self.MiniBtn = BP.ButtonInfo(self.playerToolBar, wx.ID_ANY, wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'player.gif', wx.BITMAP_TYPE_GIF), kind=wx.ITEM_NORMAL, shortHelp="Add Mini", longHelp="Add Mini")
-        self.playerToolBar.AddButton(self.MiniBtn)
-
-        self.playerToolBar.DoLayout()
-
-    def OnShapeSelection(self, event):
-        id = event.GetId()
-        if id == 5:
-            self.currentShape = 'Circle'
-            self.AddShapeBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'circle.png', wx.BITMAP_TYPE_PNG)
-        elif id == 6:
-            self.currentShape = 'Rectangle'
-            self.AddShapeBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'rectangle.png', wx.BITMAP_TYPE_PNG)
-        elif id == 7:
-            self.currentShape = 'Arc'
-            self.AddShapeBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'arc.png', wx.BITMAP_TYPE_PNG)
-
-    def OnLineSelection(self, event):
-        id = event.GetId()
-        if id == 3:
-            self.currentLine = 'Free'
-            self.DrawBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'draw.gif', wx.BITMAP_TYPE_GIF)
-            self.DrawBtn.SetShortHelp("Freehand Line Tool")
-            self.DrawBtn.SetLongHelp("Freehand Line Tool")
-        elif id == 4:
-            self.currentLine = 'Poly'
-            self.DrawBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'dash.png', wx.BITMAP_TYPE_PNG)
-            self.DrawBtn.SetShortHelp("Poly Line Tool")
-            self.DrawBtn.SetLongHelp("Poly Line Tool")
-
-    def OnFogSelection(self, event):
-        id = event.GetId()
-        if id == 1:
-            self.currentFog = 'Show'
-            self.FogToolBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'showfog.png', wx.BITMAP_TYPE_PNG)
-            self.FogToolBtn.SetShortHelp("Show Fog Tool")
-            self.FogToolBtn.SetLongHelp("Show Fog Tool")
-        elif id == 2:
-            self.currentFog = 'Hide'
-            self.FogToolBtn.Bitmap = wx.Bitmap(orpg.dirpath.dir_struct["icon"] + 'hidefog.png', wx.BITMAP_TYPE_PNG)
-            self.FogToolBtn.SetShortHelp("Hide Fog Tool")
-            self.FogToolBtn.SetLongHelp("Hide Fog Tool")
-
-### Test Stuff
-class BlankFrame(wx.Frame):
-    def __init__(self, openrpg):
-        wx.Frame.__init__(self, None, title="New Map Test Window", size=(740,480))
-
-        self.map = MapWnd(self, openrpg)
-        self.basesizer = wx.BoxSizer(wx.VERTICAL)
-        self.basesizer.Add(self.map, 1, wx.EXPAND)
-
-        self.SetSizer(self.basesizer)
-        self.SetAutoLayout(True)
-        #self.Fit()
-
-
-class BlankApp(wx.App):
-    def OnInit(self):
-        self.frame = BlankFrame()
-        self.frame.Show()
-        self.SetTopWindow(self.frame)
-
-
-        return True
-
-if __name__ == "__main__":
-    app = BlankApp(0)
-    app.MainLoop()
\ No newline at end of file
--- a/orpg/map/_canvas.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,994 +0,0 @@
-from threading import Lock
-import mimetypes
-import xml.dom.minidom as minidom
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-from orpg.tools.rgbhex import RGBHex
-
-from _object import *
-
-from _circles import MapCircle
-from _text import MapText
-from _lines import MapLine
-from _grid import GridLayer
-from _fog import FogLayer
-
-USE_BUFFER = True
-if "wxMAC" in wx.PlatformInfo:
-    USE_BUFFER = False
-
-class MapCanvas(wx.ScrolledWindow):
-    def __init__(self, parent, openrpg):
-        wx.ScrolledWindow.__init__(self, parent, wx.ID_ANY, style=wx.HSCROLL | wx.VSCROLL | wx.NO_FULL_REPAINT_ON_RESIZE | wx.SUNKEN_BORDER)
-
-        self.openrpg = openrpg
-        self.log = self.openrpg.get_component("log")
-        self.xml = self.openrpg.get_component("xml")
-        self.dir_struct = self.openrpg.get_component("dir_struct")
-        self.validate = self.openrpg.get_component("validate")
-        self.settings = self.openrpg.get_component("settings")
-        self.session = self.openrpg.get_component("session")
-        self.chat = self.openrpg.get_component("chat")
-
-        self.lock = Lock()
-
-        self.RGBHex = RGBHex()
-
-        self.toolWnd = parent
-
-        self.shift = False
-        self.ctrl = False
-
-        self.selectedObjects = []
-        self.overObjects = []
-        self._objectId = 0
-
-        self.gridLayer = GridLayer(self)
-        self.circleLayer = MapCircle(self)
-        self.textLayer = MapText(self)
-        self.lineLayer = MapLine(self)
-        self.fogLayer = FogLayer(self)
-
-        self.zOrder = {}
-        self.zOrder['tiles'] = []
-        self.zOrder["back"] = []
-        self.zOrder["front"] = []
-
-        self.bgImage = None
-        self.bgType = 'Image'
-        self.bgPath = None
-        self.backgroundColor = '#008040'
-
-        self.gridType = 'Square'
-        self.gridLines = wx.SOLID
-        self.gridSnap = True
-        self.gridSize = 60
-        self.gridColor = "#000000"
-
-        self.whiteboardColor = "#000000"
-
-        self.zoomScale = 1.0
-        self.lastZoomTime = time.time()
-        self.lastZoomScale = 1.0
-
-        self.useFog = False
-        self.fogRegion = []
-        self.fogColor = "#000000"
-
-        self.zoomScale = 1.0
-        self.lastZoomTime = time.time()
-        self.lastZoomScale = 1.0
-        self.zoomTimer = wx.Timer(self)
-        self.Bind(wx.EVT_TIMER, self.OnZoomTimer, self.zoomTimer)
-        #self.zoomTimer.Start(1000)
-
-        self.imageCache = {}
-
-        self._SetSize((1000,1000))
-
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(wx.EVT_MOUSEWHEEL, self.OnZoom)
-        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
-        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
-        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-        self.Bind(wx.EVT_MOTION, self.OnMotion)
-        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
-        self.Bind(wx.EVT_CLOSE, self.OnClose)
-        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnBackground)
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
-        self.Bind(wx.EVT_KEY_UP, self.OnKey)
-
-        self.Bind(EVT_ENTER_OBJECT, self.EnterObject)
-        self.Bind(EVT_LEAVE_OBJECT, self.LeaveObject)
-        self.Bind(EVT_SELECT_OBJECT, self.ObjectSelected)
-        self.Bind(EVT_DESELECT_OBJECT, self.ObjectDeselected)
-
-        self.roleTimer = wx.Timer(self)
-        self.Bind(wx.EVT_TIMER, self.OnRoleTimer, self.roleTimer)
-
-        wx.CallAfter(self.OnSize, None)
-
-
-    #Public API
-    def UpdateMap(self, send=True):
-        cdc = wx.ClientDC(self)
-        self.PrepareDC(cdc)
-        cdc.SetBackgroundMode(wx.TRANSPARENT)
-        if USE_BUFFER:
-            bdc = wx.BufferedDC(cdc, self._buffer)
-            bdc.Clear()
-            dc = wx.GraphicsContext.Create(bdc)
-        else:
-            cdc.Clear()
-            dc = wx.GraphicsContext.Create(cdc)
-
-
-        dc.SetPen(wx.TRANSPARENT_PEN)
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-        #Draw BG Color
-        r,g,b = self.RGBHex.rgb_tuple(self.backgroundColor)
-        brush = wx.Brush(wx.Color(r,g,b,255))
-        dc.SetBrush(brush)
-
-        path = dc.CreatePath()
-
-        dc.PushState()
-        path.AddRectangle(0, 0, self.size[0]+2, self.size[1]+2)
-        dc.DrawPath(path)
-        dc.PopState()
-
-        dc.SetBrush(wx.NullBrush)
-
-        #Set the Zoom
-        dc.Scale(self.zoomScale, self.zoomScale)
-
-        #Draw BG Image
-        if self.bgImage != None:
-            if self.bgType == 'Image':
-                dc.DrawBitmap(self.bgImage, self.offset[0], self.offset[1], self.bgImage.GetWidth(), self.bgImage.GetHeight())
-            else:
-                bmpW = self.bgImage.GetWidth()
-                bmpH = self.bgImage.GetHeight()
-
-                pos = wx.Point(self.offset[0], self.offset[1])
-                while pos.x < self.size[0]:
-                    dc.DrawBitmap(self.bgImage, pos.x, pos.y, self.bgImage.GetWidth(), self.bgImage.GetHeight())
-                    while pos.y < self.size[1]:
-                        pos.y += bmpH
-                        dc.DrawBitmap(self.bgImage, pos.x, pos.y, self.bgImage.GetWidth(), self.bgImage.GetHeight())
-                    pos.y = 0
-                    pos.x += bmpW
-
-        #Draw Tiles
-        for tile in self.zOrder['tiles']:
-            tile.Draw(dc)
-
-        #Draw Grid
-        self.gridLayer.Draw(dc)
-
-        #Draw Objects
-        for object in self.zOrder['back']:
-            object.Draw(dc)
-
-        zl = self.zOrder.keys()
-        zl.remove('back')
-        zl.remove('front')
-        zl.remove('tiles')
-        zl.sort()
-
-        for layer in zl:
-            for object in self.zOrder[layer]:
-                object.Draw(dc)
-
-        for object in self.zOrder['front']:
-            object.Draw(dc)
-
-
-        #Draw Fog
-        if self.useFog:
-            self.fogLayer.Draw(dc)
-
-        dc.SetBrush(wx.NullBrush)
-
-        dc.Scale(1/self.zoomScale, 1/self.zoomScale)
-
-        if self.zoomScale != 1.0:
-            pos = self.GetViewStart()
-            unit = self.GetScrollPixelsPerUnit()
-            pos = [pos[0]*unit[0],pos[1]*unit[1]]
-            font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
-            dc.SetFont(font, wx.BLACK)
-
-            dc.DrawText("Zoom Factor: " + str(self.zoomScale), pos[0], pos[1], dc.CreateBrush(wx.WHITE_BRUSH))
-
-    def Clear(self):
-        self._SetSize((1000,1000))
-        self.selectedObjects = []
-        self.overObjects = []
-        self._objectId = 0
-        self.bgImage = None
-        self.bgType = 'Image'
-        self.bgPath = None
-
-        self.backgroundColor = '#008040'
-        r, g, b = self.RGBHex.rgb_tuple(self.backgroundColor)
-        self.toolWnd._SetColorBtn(wx.Color(r, g, b, 255), self.toolWnd.BGColorBtn)
-
-        self.gridType = 'Square'
-        self.gridLines = wx.SOLID
-        self.gridSnap = True
-        self.gridSize = 60
-        self.gridColor = "#000000"
-
-        self.whiteboardColor = "#000000"
-        r, g, b = self.RGBHex.rgb_tuple(self.whiteboardColor)
-        self.toolWnd._SetColorBtn(wx.Color(r, g, b, 255), self.toolWnd.ColorBtn)
-
-        self.zoomScale = 1.0
-        self.lastZoomTime = time.time()
-        self.lastZoomScale = 1.0
-
-        self.useFog = False
-        self.fogRegion = []
-        self.fogColor = "#000000"
-
-        self.OnRemoveAllObjects(None)
-
-        self.toolWnd.Freeze()
-        for btn in self.toolWnd.exclusiveToolList:
-            self.toolWnd.exclusiveToolList[btn].SetToggled(False)
-
-        self.toolWnd.FogBtn.SetToggled(False)
-        self.toolWnd.SelectorBtn.SetToggled(True)
-        self.toolWnd.Thaw()
-
-    def GetNewObjectId(self):
-        return str(self._objectId+1)
-
-    #Map Events
-    def OnBackground(self, event):
-        #Dont do it
-        pass
-
-    def OnPaint(self, event):
-        if USE_BUFFER:
-            dc = wx.PaintDC(self)
-            self.PrepareDC(dc)
-            dc.DrawBitmap(self._buffer, 0, 0)
-        else:
-            event.Skip()
-
-
-    def OnSize(self, event):
-        self._buffer = wx.EmptyBitmap(self.size[0], self.size[1])
-        self._FixScroll()
-        wx.CallAfter(self.UpdateMap)
-
-
-    def OnZoom(self, event):
-        if event.GetWheelRotation() < 0:
-            self.zoomScale -= .1
-            if self.zoomScale < .5:
-                self.zoomScale = .5
-            else:
-                self.lastZoomTime = time.time()
-                self._FixScroll()
-                self.UpdateMap()
-        else:
-            self.zoomScale += .1
-
-            if self.zoomScale > 1.5:
-                self.zoomScale = 1.5
-            else:
-                self.lastZoomTime = time.time()
-                self._FixScroll()
-                self.UpdateMap()
-
-    def OnKey(self, event):
-        self.shift = False
-        self.ctrl = False
-        if event.ShiftDown():
-            self.shift = True
-        elif event.ControlDown():
-            self.ctrl = True
-
-
-    def EnterObject(self, event):
-        obj = event.GetObject()
-        self.overObjects.append(obj)
-        obj.Highlight()
-
-    def LeaveObject(self, event):
-        obj = event.GetObject()
-        try:
-            self.overObjects.remove(obj)
-        except:
-            pass
-        obj.UnHighlight()
-
-    def ObjectSelected(self, event):
-        obj = event.GetObject()
-        self.selectedObjects.append(obj)
-        try:
-            self.overObjects.remove(obj)
-        except:
-            pass
-        obj.UnHighlight()
-
-    def ObjectDeselected(self, event):
-        obj = event.GetObject()
-        try:
-            self.selectedObjects.remove(obj)
-        except:
-            pass
-        obj.Update()
-
-    def OnLeftDown(self, event):
-        dc = wx.ClientDC(self)
-        self.PrepareDC(dc)
-        pos = event.GetLogicalPosition(dc)
-        pos.x /= self.zoomScale
-        pos.y /= self.zoomScale
-
-        if self.toolWnd.AddShapeBtn.GetToggled() and self.toolWnd.currentShape == 'Circle':
-            self.circleLayer.OnLeftDown(pos)
-
-        elif self.toolWnd.AddTextBtn.GetToggled():
-            self.textLayer.OnLeftDown(pos)
-
-        elif self.toolWnd.DrawBtn.GetToggled():
-            self.lineLayer.OnLeftDown(pos)
-
-        elif self.toolWnd.SelectorBtn.GetToggled() and (self.selectedObjects == [] or self.ctrl or self.shift) and not (self.useFog and self.fogLayer.region.Contains(pos.x, pos.y) and not self.toolWnd.gmToolBar.IsShown()):
-            self.initiatPos = pos
-            self.lxd = 0
-            self.lyd = 0
-            if len(self.overObjects) == 0:
-                return
-            elif len(self.overObjects) == 1:
-                self.overObjects[0].Select()
-            else:
-                if not self.shift:
-                    menu = wx.Menu("Object Selection")
-                    id = 0
-                    for obj in self.overObjects:
-                        menu.Append(id, obj.GetName())
-                        id += 1
-
-                    def selectmenu(event):
-                        id = event.GetId()
-                        self.overObjects[id].Select()
-                        self.Unbind(wx.EVT_MENU)
-
-                    self.Bind(wx.EVT_MENU, selectmenu)
-                    self.PopupMenu(menu)
-                else:
-                    for i in xrange(len(self.overObjects)):
-                        self.overObjects[0].Select()
-
-        elif self.toolWnd.SelectorBtn.GetToggled() and not self.selectedObjects == []:
-            xd = (self.initiatPos.x+pos.x)*(self.initiatPos.x+pos.x)
-            yd = (self.initiatPos.y+pos.y)*(self.initiatPos.y+pos.y)
-
-            for i in xrange(len(self.selectedObjects)):
-                self.selectedObjects[0].Deselect()
-
-        elif self.toolWnd.FogToolBtn.GetToggled():
-            self.fogLayer.OnLeftDown(pos)
-
-    def OnLeftDClick(self, event):
-        dc = wx.ClientDC(self)
-        self.PrepareDC(dc)
-        pos = event.GetLogicalPosition(dc)
-        pos.x /= self.zoomScale
-        pos.y /= self.zoomScale
-
-        if self.toolWnd.DrawBtn.GetToggled():
-            self.lineLayer.OnLeftDClick(pos)
-
-    def OnLeftUp(self, event):
-        dc = wx.ClientDC(self)
-        self.PrepareDC(dc)
-        pos = event.GetLogicalPosition(dc)
-        pos.x /= self.zoomScale
-        pos.y /= self.zoomScale
-
-        if self.toolWnd.AddShapeBtn.GetToggled() and self.toolWnd.currentShape == 'Circle':
-            self.circleLayer.OnLeftUp(pos)
-
-        elif self.toolWnd.FogToolBtn.GetToggled():
-            self.fogLayer.OnLeftUp(pos)
-
-        elif self.toolWnd.DrawBtn.GetToggled():
-            self.lineLayer.OnLeftUp(pos)
-
-        elif self.toolWnd.SelectorBtn.GetToggled() and self.selectedObjects == []:
-            rgn = wx.Region(self.initiatPos.x, self.initiatPos.y, self.lxd, self.lyd)
-
-            for object in self.zOrder['back']:
-                if rgn.Contains(object.start.x, object.start.y):
-                    object.Select()
-
-            zl = self.zOrder.keys()
-            zl.remove('back')
-            zl.remove('front')
-            zl.remove('tiles')
-            zl.sort()
-
-            for layer in zl:
-                for object in self.zOrder[layer]:
-                    if rgn.Contains(object.start.x, object.start.y):
-                        object.Select()
-
-            for object in self.zOrder['front']:
-                if rgn.Contains(object.start.x, object.start.y):
-                    object.Select()
-
-            self.lxd = 0
-            self.lyd = 0
-            self.initiatPos = pos
-        self.Refresh()
-
-    def OnMotion(self, event):
-        dc = wx.ClientDC(self)
-        self.PrepareDC(dc)
-        pos = event.GetLogicalPosition(dc)
-        pos.x /= self.zoomScale
-        pos.y /= self.zoomScale
-
-
-        #HitTest
-        for object in self.zOrder['back']:
-            object.HitTest(pos)
-
-        zl = self.zOrder.keys()
-        zl.remove('back')
-        zl.remove('front')
-        zl.remove('tiles')
-        zl.sort()
-
-        for layer in zl:
-            for object in self.zOrder[layer]:
-                object.HitTest(pos)
-
-        for object in self.zOrder['front']:
-            object.HitTest(pos)
-
-        if self.toolWnd.AddShapeBtn.GetToggled() and event.m_leftDown and self.toolWnd.currentShape == 'Circle':
-            self.circleLayer.OnMotion(pos)
-
-        elif self.toolWnd.DrawBtn.GetToggled() and self.lineLayer.start != wx.Point(0,0):
-            self.lineLayer.OnMotion(pos)
-
-        elif self.toolWnd.SelectorBtn.GetToggled() and self.selectedObjects != [] and not (self.ctrl or self.shift):
-            xd = (pos.x-self.initiatPos.x)
-            yd = (pos.y-self.initiatPos.y)
-            for obj in self.selectedObjects:
-                obj.start.x += xd
-                obj.start.y += yd
-                obj.Update()
-                self.initiatPos = pos
-
-
-        elif self.toolWnd.SelectorBtn.GetToggled() and self.selectedObjects == [] and event.m_leftDown:
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            pen = wx.Pen(wx.BLACK, 3, wx.DOT)
-            dc.SetPen(pen)
-            dc.SetLogicalFunction(wx.INVERT)
-
-            xd = (pos.x-self.initiatPos.x)
-            yd = (pos.y-self.initiatPos.y)
-
-            if self.lxd != 0 and self.lyd != 0:
-                r = wx.Rect(self.initiatPos.x, self.initiatPos.y, self.lxd, self.lyd)
-                dc.DrawRectangleRect(r)
-
-            self.lxd = xd
-            self.lyd = yd
-            r = wx.Rect(self.initiatPos.x, self.initiatPos.y, self.lxd, self.lyd)
-            dc.DrawRectangleRect(r)
-
-        elif (self.toolWnd.FogToolBtn.GetToggled()) and event.m_leftDown:
-            self.fogLayer.OnMotion(pos)
-
-    def OnRightDown(self, event):
-        mapmenu = wx.Menu()
-
-        item = wx.MenuItem(mapmenu, wx.ID_ANY, "Load Map", "Load Map")
-        #self.Bind(wx.EVT_MENU, self.OnOpenBtn, item)
-        mapmenu.AppendItem(item)
-
-        item = wx.MenuItem(mapmenu, wx.ID_ANY, "Save Map", "Save Map")
-        #self.Bind(wx.EVT_MENU, self.OnSaveBtn, item)
-        mapmenu.AppendItem(item)
-
-        item = wx.MenuItem(mapmenu, wx.ID_ANY, "Default Map", "Default Map")
-        self.Bind(wx.EVT_MENU, self.OnDefaultBtn, item)
-        mapmenu.AppendItem(item)
-
-        item = wx.MenuItem(mapmenu, wx.ID_ANY, "Map Properties", "Map Properties")
-        #self.Bind(wx.EVT_MENU, OnMapPropsBtn, item)
-        mapmenu.AppendItem(item)
-
-        bgmenu = wx.Menu()
-
-        item = wx.MenuItem(bgmenu, wx.ID_ANY, "Change Background Image", "Change Background Image")
-        self.Bind(wx.EVT_MENU, self.OnBGBtn, item)
-        bgmenu.AppendItem(item)
-
-        item = wx.MenuItem(bgmenu, wx.ID_ANY, "Change Background Color", "Change Background Color")
-        self.Bind(wx.EVT_MENU, self.OnBGColorBtn, item)
-        bgmenu.AppendItem(item)
-
-        item = wx.MenuItem(bgmenu, wx.ID_ANY, "Grid Properties", "Grid Properties")
-        #self.Bind(wx.EVT_MENU, self.OnGridBtn, item)
-        bgmenu.AppendItem(item)
-
-        fogmenu = wx.Menu()
-
-        item = wx.MenuItem(fogmenu, wx.ID_ANY, "Toggle Fog", "Toggle Fog")
-        self.Bind(wx.EVT_MENU, self.OnFogBtn, item)
-        fogmenu.AppendItem(item)
-
-        item = wx.MenuItem(fogmenu, wx.ID_ANY, "Fog Color", "Fog Color")
-        self.Bind(wx.EVT_MENU, self.OnFogColorBtn, item)
-        fogmenu.AppendItem(item)
-
-        menu = wx.Menu()
-
-        if self.toolWnd.gmToolBar.IsShown():
-            menu.AppendMenu(wx.ID_ANY, "Map", mapmenu)
-            menu.AppendMenu(wx.ID_ANY, "Background", bgmenu)
-            menu.AppendMenu(wx.ID_ANY, "Fog", fogmenu)
-            menu.AppendSeparator()
-            item = wx.MenuItem(menu, wx.ID_ANY, "Miniture Properties", "Miniture Properties")
-            #self.Bind(wx.EVT_MENU, self.OnColorBtn, item)
-            menu.AppendItem(item)
-            menu.AppendSeparator()
-
-        item = wx.MenuItem(menu, wx.ID_ANY, "Whiteboard Color", "Whiteboard Color")
-        self.Bind(wx.EVT_MENU, self.OnColorBtn, item)
-        menu.AppendItem(item)
-
-
-        def ObjectMenu(event):
-            id = event.GetId()
-            objid = int(menu.GetHelpString(id))
-            menuname = menu.GetLabel(id)
-            obj = self.overObjects[objid]
-
-            if menuname == "Move To Back":
-                self.MoveToBack(obj)
-
-            elif menuname == "Move Back":
-                self.MoveBack(obj)
-
-            elif menuname == "Move Forward":
-                self.MoveForward(obj)
-
-            elif menuname == "Move To Front":
-                self.MoveToFront(obj)
-
-            elif menuname == "Remove":
-                self.zOrder[obj.zOrder].remove(obj)
-                obj.Update()
-
-            self.Unbind(wx.EVT_MENU)
-            self.overObjects.remove(obj)
-
-
-        if len(self.overObjects):
-            menu.AppendSeparator()
-
-        id = 0
-        for obj in self.overObjects:
-            if obj.IsShown() or self.toolWnd.gmToolBar.IsShown():
-                objmenu = wx.Menu()
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Move To Back", str(id))
-                self.Bind(wx.EVT_MENU, ObjectMenu, item)
-                objmenu.AppendItem(item)
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Move Back", str(id))
-                self.Bind(wx.EVT_MENU, ObjectMenu, item)
-                objmenu.AppendItem(item)
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Move Forward", str(id))
-                self.Bind(wx.EVT_MENU, ObjectMenu, item)
-                objmenu.AppendItem(item)
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Move To Front", str(id))
-                self.Bind(wx.EVT_MENU, ObjectMenu, item)
-                objmenu.AppendItem(item)
-                objmenu.AppendSeparator()
-                if obj.IsShown():
-                    item = wx.MenuItem(objmenu, wx.ID_ANY, "Hide", str(id))
-                    self.Bind(wx.EVT_MENU, obj.Hide, item)
-                    objmenu.AppendItem(item)
-                    objmenu.AppendSeparator()
-                elif self.toolWnd.gmToolBar.IsShown():
-                    item = wx.MenuItem(objmenu, wx.ID_ANY, "Show", str(id))
-                    self.Bind(wx.EVT_MENU, obj.Show, item)
-                    objmenu.AppendItem(item)
-                    objmenu.AppendSeparator()
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Remove", str(id))
-                self.Bind(wx.EVT_MENU, ObjectMenu, item)
-                objmenu.AppendItem(item)
-                item = wx.MenuItem(objmenu, wx.ID_ANY, "Properties", str(id))
-                self.Bind(wx.EVT_MENU, obj.ShowProperties, item)
-                objmenu.AppendItem(item)
-                menu.AppendMenu(wx.ID_ANY, obj.GetName(), objmenu)
-
-        menu.AppendSeparator()
-        item = wx.MenuItem(menu, wx.ID_ANY, "Remove All Objects", "Remove All Whiteboard Items")
-        self.Bind(wx.EVT_MENU, self.OnRemoveAllObjects, item)
-        menu.AppendItem(item)
-
-        self.PopupMenu(menu)
-
-
-    def OnRemoveAllObjects(self, event):
-        for layer in self.zOrder:
-            for i in xrange(len(self.zOrder[layer])):
-                del self.zOrder[layer][0]
-
-        self.zOrder = {}
-        self.zOrder['tiles'] = []
-        self.zOrder["back"] = []
-        self.zOrder["front"] = []
-        if event != None:
-            self.UpdateMap()
-
-    def MoveToBack(self, object):
-        self.zOrder[object.zOrder].remove(object)
-        self.zOrder['back'].append(object)
-        object.zOrder = 'back'
-        self.UpdateMap()
-
-    def MoveToFront(self, object):
-        self.zOrder[object.zOrder].remove(object)
-        self.zOrder['front'].append(object)
-        object.zOrder = 'front'
-        self.UpdateMap()
-
-    def MoveBack(self, object):
-        self.zOrder[object.zOrder].remove(object)
-
-        zl = self.zOrder.keys()
-        zl.remove('back')
-        zl.remove('front')
-        zl.remove('tiles')
-        zl.sort()
-        lzo = 1
-        if len(zl):
-            lzo = zl.pop()
-
-        if object.zOrder == 'back' or object.zOrder == 1:
-            self.zOrder['back'].append(object)
-            object.zOrder = 'back'
-        elif object.zOrder == 'front':
-            if not self.zOrder.has_key(lzo):
-                self.zOrder[lzo] = []
-            self.zOrder[lzo].append(object)
-            object.zOrder = lzo
-        else:
-            object.zOrder -= 1
-            if not self.zOrder.has_key(object.zOrder):
-                self.zOrder[object.zOrder] = []
-            self.zOrder[object.zOrder].append(object)
-        self.UpdateMap()
-
-    def MoveForward(self, object):
-        self.zOrder[object.zOrder].remove(object)
-
-        zl = self.zOrder.keys()
-        zl.remove('back')
-        zl.remove('front')
-        zl.remove('tiles')
-        zl.sort()
-        lzo = 1
-        if len(zl):
-            lzo = zl.pop()
-
-        if object.zOrder == 'back':
-            if not self.zOrder.has_key(1):
-                self.zOrder[1] = []
-            self.zOrder[1].append(object)
-            object.zOrder = 1
-        elif z == 'front':
-            self.zOrder['front'].append(object)
-            object.zOrder = 'front'
-        else:
-            object.zOrder += 1
-            if not self.zOrder.has_key(object.zOrder):
-                self.zOrder[object.zOrder] = []
-            self.zOrder[object.zOrder].append(object)
-        self.UpdateMap()
-
-    def OnScroll(self, event):
-        event.Skip()
-        self.Refresh()
-
-    def OnZoomTimer(self, event):
-        if (time.time() - self.lastZoomTime) >= 3 and self.lastZoomScale != self.zoomScale:
-            #Send Zoome Notice to other clients
-            self.lastZoomTime = time.time()
-            self.lastZoomScale = self.zoomScale
-
-    def OnRoleTimer(self, event):
-        #Figure out the users role
-        if self.session.my_role() == self.session.ROLE_GM:
-            self.role = 'GM'
-        elif self.session.my_role() == self.session.ROLE_PLAYER:
-            self.role = 'Player'
-        else:
-            self.role = 'Lurker'
-
-        if self.role == 'GM' and not self.toolWnd.gmToolBar.IsShown() and not (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            self.toolWnd.Freeze()
-            self.toolWnd.gmToolBar.Show()
-            self.toolWnd.Thaw()
-        elif self.role == 'Player' and not (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            if self.toolWnd.gmToolBar.IsShown():
-                self.toolWnd.Freeze()
-                self.toolWnd.gmToolBar.Hide()
-                self.toolWnd.Thaw()
-
-            if not self.toolWnd.playerToolBar.IsShown():
-                self.toolWnd.Freeze()
-                self.toolWnd.playerToolBar.Show()
-                self.toolWnd.Thaw()
-        elif self.role == 'Lurker' or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
-            if self.toolWnd.playerToolBar.IsShown():
-                self.toolWnd.Freeze()
-                self.toolWnd.gmToolBar.Hide()
-                self.toolWnd.playerToolBar.Hide()
-                self.toolWnd.Thaw()
-
-        try:
-            self.toolWnd.Layout()
-        except:
-            pass
-
-    def OnClose(self, event):
-        self.zoomTimer.Stop()
-        self.roleTimer.Stop()
-        event.Skip()
-
-    #Toolbar Events
-    def OnDefaultBtn(self, event):
-        self.Clear()
-        wx.CallAfter(self.UpdateMap)
-
-    def OnColorBtn(self, event):
-        newcolor = self.RGBHex.do_hex_color_dlg(self.toolWnd)
-        if newcolor == None:
-            return
-
-        self.whiteboardColor = newcolor
-        r, g, b = self.RGBHex.rgb_tuple(self.whiteboardColor)
-        self.toolWnd._SetColorBtn(wx.Color(r, g, b, 255), self.toolWnd.ColorBtn)
-
-    def OnBGColorBtn(self, event):
-        newcolor = self.RGBHex.do_hex_color_dlg(self.toolWnd)
-        if newcolor == None:
-            return
-
-        self.backgroundColor = newcolor
-        r, g, b = self.RGBHex.rgb_tuple(self.backgroundColor)
-        self.toolWnd._SetColorBtn(wx.Color(r, g, b, 255), self.toolWnd.BGColorBtn)
-        self.UpdateMap()
-
-    def OnFogColorBtn(self, event):
-        newcolor = self.RGBHex.do_hex_color_dlg(self.toolWnd)
-        if newcolor == None:
-            return
-
-        self.fogColor = newcolor
-        r, g, b = self.RGBHex.rgb_tuple(self.fogColor)
-        self.toolWnd._SetColorBtn(wx.Color(r, g, b, 255), self.toolWnd.FogColorBtn)
-        self.UpdateMap()
-
-    def OnExlusiveBtn(self, event):
-        id = event.GetId()
-        #This is backwards because the Toggle Switch does not get set until AFTER The mouse gets released
-        if not self.toolWnd.exclusiveToolList[id].GetToggled():
-            self.toolWnd.Freeze()
-            #Disable all mutualy exclusive tools
-            for btn in self.toolWnd.exclusiveToolList:
-                if self.toolWnd.exclusiveToolList[btn].GetId() != id:
-                    self.toolWnd.exclusiveToolList[btn].SetToggled(False)
-            self.toolWnd.Thaw()
-        else:
-            wx.CallAfter(self.toolWnd.SelectorBtn.SetToggled, True)
-
-    def OnFogBtn(self, event):
-        if not self.toolWnd.FogBtn.GetToggled():
-            self.useFog = True
-        else:
-            self.useFog = False
-            self.toolWnd.Freeze()
-            self.toolWnd.SelectorBtn.SetToggled(True)
-            self.toolWnd.FogToolBtn.SetToggled(False)
-            self.toolWnd.Thaw()
-        self.fogRegion = []
-        self.UpdateMap()
-
-    def OnBGBtn(self, event):
-        dlg = wx.Dialog(self.toolWnd, wx.ID_ANY, title="Background Properties")
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        filename = wx.TextCtrl(dlg, wx.ID_ANY)
-        filename.Hide()
-
-        bgpath = wx.TextCtrl(dlg, wx.ID_ANY)
-        if self.bgPath != None:
-            bgpath.SetValue(self.bgPath)
-
-        bgtype = wx.Choice(dlg, wx.ID_ANY, choices=['Image', 'Texture'])
-        bgtype.SetStringSelection(self.bgType)
-
-        browsebtn = wx.Button(dlg, wx.ID_ANY, "Browse")
-        okbtn = wx.Button(dlg, wx.ID_OK)
-        cancelbtn = wx.Button(dlg, wx.ID_CANCEL)
-
-        sizer.Add(wx.StaticText(dlg, wx.ID_ANY, "Image Path"), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 2)
-        sizer.Add(bgpath, 0, wx.EXPAND|wx.ALL, 3)
-        sizer.Add(wx.StaticText(dlg, wx.ID_ANY, "Image Type"), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 2)
-        sizer.Add(bgtype, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
-        sizer.Add(browsebtn, 0, wx.EXPAND|wx.ALL, 2)
-        sizer.Add(okbtn, 0, wx.EXPAND|wx.ALL, 3)
-        sizer.Add(cancelbtn, 0, wx.EXPAND|wx.ALL, 2)
-
-        dlg.SetSizer(sizer)
-        dlg.SetAutoLayout(True)
-        dlg.Fit()
-
-        def OnBrowse(event):
-            filedlg = wx.FileDialog(self, "Select an Image File", self.dir_struct["user"], wildcard="Image files (*.bmp, *.gif, *.jpg, *.png)|*.bmp;*.gif;*.jpg;*.png", style=wx.HIDE_READONLY|wx.OPEN)
-            if filedlg.ShowModal() != wx.ID_OK:
-                filedlg.Destroy()
-                return
-
-            bgpath.SetValue(filedlg.GetPath())
-            filename.SetValue(filedlg.GetFilename())
-
-        dlg.Bind(wx.EVT_BUTTON, OnBrowse, browsebtn)
-        dlg.Show()
-
-        if not dlg.ShowModal() == wx.ID_OK:
-            dlg.Destroy()
-            return
-
-        self.bgType = bgtype.GetStringSelection()
-
-        if bgpath.GetValue().lower().find('http:') == -1:
-            file = open(bgpath.GetValue(), "rb")
-            imgdata = file.read()
-            file.close()
-
-            (imgtype,j) = mimetypes.guess_type(filename.GetValue())
-
-            postdata = urllib.urlencode({'filename':filename.GetValue(), 'imgdata':imgdata, 'imgtype':imgtype})
-
-            thread.start_new_thread(self.__Upload, (postdata, bgpath.GetValue(), "Background"))
-        else:
-            self.bgImage = self._LoadImage(bgpath.GetValue())
-            self.UpdateMap()
-
-
-    #Private Methods
-    def _SetSize(self, size):
-        if size[0] == -1:
-            size[0] = self.size[0]
-        if size[1] == -1:
-            size[1] = self.size[1]
-
-        if size[0] < 300:
-            size = (300, size[1])
-        if size[1] < 300:
-            size = (size[0], 300)
-
-        size1  = self.GetClientSizeTuple()
-
-        if size[0] < size1[0]:
-            size = (size1[0], size[1])
-        if size[1] < size1[1]:
-            size = (size[0], size1[1])
-
-        self.sizeChanged = 1
-        self.size = size
-        self._FixScroll()
-
-    def _FixScroll(self):
-        scale = self.zoomScale
-        pos = self.GetViewStart()
-        unit = self.GetScrollPixelsPerUnit()
-        pos = [pos[0]*unit[0],pos[1]*unit[1]]
-        size = self.GetClientSize()
-        unit = [10*scale,10*scale]
-        if (unit[0] == 0 or unit[1] == 0):
-            return
-        pos[0] /= unit[0]
-        pos[1] /= unit[1]
-        mx = [int(self.size[0]*scale/unit[0])+1, int(self.size[1]*scale/unit[1]+1)]
-        self.SetScrollbars(unit[0], unit[1], mx[0], mx[1], pos[0], pos[1])
-
-    def _LoadImage(self, path, miniId=None):
-        if self.imageCache.has_key(path):
-            return self.imageCache[path]
-
-        while len(self.imageCache) > int(self.settings.get_setting("ImageCacheSize")):
-            keys = self.imageCache.keys()
-            del self.imageCache[keys[0]]
-
-
-        thread.start_new_thread(self.__DownloadImage, (path, miniId))
-
-        return wx.Bitmap(orpg.dirpath.dir_struct["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)
-
-    def _ClearCache(self):
-        for key in self.imageCache:
-            del self.imageCache[key]
-
-    #Threads
-    def __Upload(self, postdata, filename, type="Background"):
-        self.lock.acquire()
-
-        url = self.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 type == 'Background':
-                    self.bgImage = self._LoadImage(path)
-                    self.bgPath = path
-
-                else:
-                    self.minis.append(self.mapLayer.AddMiniture(path))
-
-                self.UpdateMap()
-
-            else:
-                self.chat.InfoPost(xml_dom.getAttribute('msg'))
-        except Exception, e:
-            print e
-            print recvdata
-
-        self.lock.release()
-
-    def __DownloadImage(self, path, miniId):
-        self.lock.acquire()
-
-        uriPath = urllib.unquote(path)
-        try:
-            data = urllib.urlretrieve(uriPath)
-
-            if data[0] and data[1].getmaintype() == "image":
-                imageType = data[1].gettype()
-                img = wx.ImageFromMime(data[0], imageType).ConvertToBitmap()
-                self.imageCache[path] = img
-
-                if miniId == None:
-                    self.bgImage = img
-                    if self.bgType == 'Image':
-                        self._SetSize((img.GetHeight(), img.GetWidth()))
-
-                else:
-                    mini = self.GetMiniById(miniId)
-                    mini.image = img
-
-                self.UpdateMap()
-        except Exception, e:
-            self.chat.InfoPost("Unable to resolve/open the specified URI; image was NOT laoded:" + path)
-
-        urllib.urlcleanup()
-        self.lock.release()
\ No newline at end of file
--- a/orpg/map/_circles.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-from math import sqrt
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-
-from _object import MapObject
-
-class MapCircle(MapObject):
-    def __init__(self, canvas, center=wx.Point(0,0), radius=0, color="#000000"):
-        MapObject.__init__(self, canvas=canvas)
-        self.start = center
-        self.radius = int(radius)
-        self.color = color
-
-        r, g, b = self.RGBHex.rgb_tuple(self.color)
-        self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-
-        self.id = 'circle-' + self.canvas.GetNewObjectId()
-
-
-    def Draw(self, dc):
-        path = dc.CreatePath()
-
-        if not self.highlighed:
-            c = self.color
-        else:
-            c = self.hcolor
-        r, g, b = self.RGBHex.rgb_tuple(c)
-
-        pen = wx.TRANSPARENT_PEN
-        brush = wx.TRANSPARENT_BRUSH
-        if self.IsShown():
-            brush = wx.Brush(wx.Color(r, g, b, 128))
-            pen = wx.Pen(wx.Color(r, g, b, 128))
-        elif self.canvas.toolWnd.gmToolBar.IsShown():
-            brush = wx.Brush(wx.Color(r, g, b, 40))
-            pen = wx.Pen(wx.Color(r, g, b, 40))
-            font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
-            dc.SetFont(font, wx.RED)
-            w, h = dc.GetTextExtent("Hidden")
-            dc.DrawText("Hidden", self.start.x-(w/2), self.start.y-(h/2), dc.CreateBrush(wx.WHITE_BRUSH))
-
-        dc.SetBrush(brush)
-        dc.SetPen(pen)
-
-        path.AddCircle(self.start.x, self.start.y, self.radius)
-        path.CloseSubpath()
-        dc.DrawPath(path)
-
-        dc.SetBrush(wx.NullBrush)
-        dc.SetPen(wx.NullPen)
-
-        if self.selected:
-            self.DrawSelection(dc)
-
-    def DrawSelection(self, dc):
-        dc.SetBrush(wx.GREEN_BRUSH)
-        dc.SetPen(wx.GREEN_PEN)
-        path = dc.CreatePath()
-
-        path.AddRectangle(self.start.x-self.radius, self.start.y-self.radius, 5, 5)
-        path.AddRectangle(self.start.x-self.radius, self.start.y+self.radius, 5, 5)
-        path.AddRectangle(self.start.x+self.radius, self.start.y-self.radius, 5, 5)
-        path.AddRectangle(self.start.x+self.radius, self.start.y+self.radius, 5, 5)
-
-        path.MoveToPoint(self.start.x, self.start.y)
-        path.AddLineToPoint(self.start.x-10, self.start.y)
-        path.MoveToPoint(self.start.x, self.start.y)
-        path.AddLineToPoint(self.start.x, self.start.y+10)
-        path.MoveToPoint(self.start.x, self.start.y)
-        path.AddLineToPoint(self.start.x+10, self.start.y)
-        path.MoveToPoint(self.start.x, self.start.y)
-        path.AddLineToPoint(self.start.x, self.start.y-10)
-
-        dc.DrawPath(path)
-
-        dc.SetBrush(wx.NullBrush)
-        dc.SetPen(wx.NullPen)
-
-    def InObject(self, pos):
-        xd = (self.start.x-pos.x)*(self.start.x-pos.x)
-        yd = (self.start.y-pos.y)*(self.start.y-pos.y)
-        distance = sqrt(xd+yd)
-
-        if distance <= self.radius:
-            return True
-
-        return False
-
-    def GetName(self):
-        return 'Circle: ' + str(self.id) + ' Radius:' + str(self.radius) + ' Color:' + self.color
-
-    def ShowProperties(self, event):
-        dlg = wx.Dialog(self.canvas, wx.ID_ANY, "Circle Properties")
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        radius = wx.TextCtrl(dlg, wx.ID_ANY)
-        radius.SetValue(str(self.radius))
-
-        colorbtn = wx.Button(dlg, wx.ID_ANY, "Color")
-        colorbtn.SetForegroundColour(self.hcolor)
-
-        def ColorBtn(event):
-            newcolor = self.RGBHex.do_hex_color_dlg(self.canvas)
-            if newcolor == None:
-                return
-
-            colorbtn.SetForegroundColour(newcolor)
-            dlg.Unbind(wx.EVT_BUTTON)
-
-        dlg.Bind(wx.EVT_BUTTON, ColorBtn, colorbtn)
-
-        sizer.Add(wx.StaticText(dlg, wx.ID_ANY, "Radius:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 2)
-        sizer.Add(radius, 0, wx.EXPAND|wx.ALL, 3)
-        sizer.Add(colorbtn, 0, wx.ALL, 2)
-        sizer.Add(wx.Button(dlg, wx.ID_OK), 0, wx.ALL, 3)
-
-        dlg.SetSizer(sizer)
-        dlg.SetAutoLayout(True)
-        dlg.Fit()
-        dlg.Show()
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.radius = int(radius.GetValue())
-            r,g,b = colorbtn.GetForegroundColour().Get()
-            self.color = self.RGBHex.hexstring(r, g, b)
-            self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-            self.Update(send=True, action="update")
-
-
-    def OnLeftDown(self, pos):
-        self.start = pos
-        self.lastRadius = 0
-        self.radius = 0
-
-    def OnMotion(self, pos):
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        dc.SetLogicalFunction(wx.EQUIV)
-        dc.SetUserScale(self.canvas.zoomScale, self.canvas.zoomScale)
-
-
-        if self.radius > 0:
-            dc.DrawCircle(self.start.x, self.start.y, self.radius)
-
-        xd = (self.start.x-pos.x)*(self.start.x-pos.x)
-        yd = (self.start.y-pos.y)*(self.start.y-pos.y)
-        self.radius = sqrt(xd+yd)
-
-        #self.lastRadius = self.radius
-        dc.DrawCircle(self.start.x, self.start.y, self.radius)
-
-    def OnLeftUp(self, pos):
-        xd = (self.start.x-pos.x)*(self.start.x-pos.x)
-        yd = (self.start.y-pos.y)*(self.start.y-pos.y)
-        radius = sqrt(xd+yd)
-
-        if radius > 15:
-            self.canvas.zOrder['front'].append(MapCircle(self.canvas, self.start, radius, self.canvas.whiteboardColor))
-            self.Update(send=True, action='new')
-        self.lastRadius = 0
-        self.start = wx.Point(0,0)
-        self.radius = 0
-
-    def _toxml(self, action="update"):
-        return ''
\ No newline at end of file
--- a/orpg/map/_fog.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-from math import sqrt
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-
-from _object import MapObject
-
-class FogLayer(MapObject):
-    def __init__(self, canvas):
-        MapObject.__init__(self, canvas=canvas)
-
-    def Draw(self, dc):
-        path = dc.CreatePath()
-        r, g, b = self.RGBHex.rgb_tuple(self.canvas.fogColor)
-        if self.canvas.toolWnd.gmToolBar.IsShown():
-            brush = wx.Brush(wx.Color(r, g, b, 128))
-        else:
-            brush = wx.Brush(wx.Color(r, g, b, 255))
-        dc.SetBrush(brush)
-
-        self.region = wx.Region(0, 0, self.canvas.size[0]+2, self.canvas.size[1]+2)
-
-        points = []
-        lp = 's'
-        for point in self.canvas.fogRegion:
-            if point == 's' or point == 'h':
-                if lp == 's' and len(points) > 0:
-                    self.region.XorRegion(wx.RegionFromPoints(points))
-                    self.region.SubtractRegion(wx.RegionFromPoints(points))
-                elif len(points) > 0:
-                    self.region.UnionRegion(wx.RegionFromPoints(points))
-                lp = point
-                points = []
-            else:
-                points.append((point.x, point.y))
-
-        if len(points) > 0:
-            if lp == 's':
-                self.region.XorRegion(wx.RegionFromPoints(points))
-                self.region.SubtractRegion(wx.RegionFromPoints(points))
-            else:
-                self.region.UnionRegion(wx.RegionFromPoints(points))
-
-        dc.ClipRegion(self.region)
-
-        dc.DrawRectangle(0, 0, self.canvas.size[0]+2, self.canvas.size[1]+2)
-
-        dc.SetBrush(wx.NullBrush)
-
-    def OnLeftDown(self, pos):
-        self.start = pos
-        self.lastPoint = pos
-        if self.canvas.toolWnd.currentFog == 'Show':
-            self.canvas.fogRegion.append('s')
-        else:
-            self.canvas.fogRegion.append('h')
-        self.canvas.fogRegion.append(pos)
-
-    def OnMotion(self, pos):
-        cdc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(cdc)
-
-        dc = wx.GraphicsContext.Create(cdc)
-        dc.Scale(self.canvas.zoomScale, self.canvas.zoomScale)
-
-        dc.SetPen(wx.WHITE_PEN)
-
-        path = dc.CreatePath()
-
-        xd = (self.lastPoint.x-pos.x)*(self.lastPoint.x-pos.x)
-        yd = (self.lastPoint.y-pos.y)*(self.lastPoint.y-pos.y)
-        distance = sqrt(xd+yd)
-
-        if distance > 5:
-            path.MoveToPoint(self.lastPoint.x, self.lastPoint.y)
-            path.AddLineToPoint(pos.x, pos.y)
-
-            self.canvas.fogRegion.append(pos)
-            self.lastPoint = pos
-
-        path.CloseSubpath()
-        dc.StrokePath(path)
-
-        dc.SetPen(wx.NullPen)
-
-    def OnLeftUp(self, pos):
-        self.canvas.fogRegion.append(pos)
-        self.canvas.fogRegion.append(self.start)
-        self.canvas.UpdateMap()
-
--- a/orpg/map/_grid.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-from orpg.tools.rgbhex import RGBHex
-
-class GridLayer:
-    def __init__(self, canvas):
-        self.canvas = canvas
-        self.RGBHex = RGBHex()
-
-    def Draw(self, dc):
-        r, g, b = self.RGBHex.rgb_tuple(self.canvas.gridColor)
-        pen = wx.Pen(wx.Color(r, g, b, 255), 1, self.canvas.gridLines)
-        dc.SetPen(pen)
-
-        path = dc.CreatePath()
-
-        if self.canvas.gridType == 'Square':
-            self._DrawSquare(dc, path)
-
-        dc.SetPen(wx.NullPen)
-
-    def _DrawSquare(self, dc, path):
-        path.MoveToPoint(0, 0)
-        y = 0
-        while y < self.canvas.size[1]:
-            path.AddLineToPoint(self.canvas.size[0], y)
-            y += self.canvas.gridSize
-            path.MoveToPoint(0, y)
-
-        path.MoveToPoint(0, 0)
-        x = 0
-        while x < self.canvas.size[0]:
-            path.AddLineToPoint(x, self.canvas.size[0])
-            x += self.canvas.gridSize
-            path.MoveToPoint(x, 0)
-
-        dc.StrokePath(path)
\ No newline at end of file
--- a/orpg/map/_lines.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-from math import sqrt
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-
-from _object import MapObject
-
-class MapLine(MapObject):
-    def __init__(self, canvas, start=wx.Point(0,0), width=1, color="#000000", points=[]):
-        MapObject.__init__(self, canvas=canvas)
-        self.start = wx.Point(start[0], start[1])
-        self.color = color
-        self.points = points
-        self.width = width
-
-        r, g, b = self.RGBHex.rgb_tuple(self.color)
-        self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-
-        self.id = 'line-' + self.canvas.GetNewObjectId()
-
-
-    def Draw(self, dc):
-        path = dc.CreatePath()
-
-        if not self.highlighed:
-            c = self.color
-        else:
-            c = self.hcolor
-        r, g, b = self.RGBHex.rgb_tuple(c)
-
-        pen = wx.Pen(wx.Color(r, g, b, 0), self.width)
-        if self.IsShown():
-            pen = wx.Pen(wx.Color(r, g, b, 255), self.width)
-        elif self.canvas.toolWnd.gmToolBar.IsShown():
-            pen = wx.Pen(wx.Color(r, g, b, 40), self.width)
-        dc.SetPen(pen)
-
-        dc.DrawLines(self.points)
-
-        dc.SetBrush(wx.NullBrush)
-        dc.SetPen(wx.NullPen)
-
-        if self.selected:
-            self.DrawSelection(dc)
-
-    def DrawSelection(self, dc):
-        dc.SetBrush(wx.GREEN_BRUSH)
-        dc.SetPen(wx.GREEN_PEN)
-        path = dc.CreatePath()
-
-        dc.DrawPath(path)
-
-        dc.SetBrush(wx.NullBrush)
-        dc.SetPen(wx.NullPen)
-
-    def InObject(self, pos):
-        for point in self.points:
-            xd = (point[0]-pos.x)*(point[0]-pos.x)
-            yd = (point[1]-pos.y)*(point[1]-pos.y)
-            distance = sqrt(xd+yd)
-
-            if distance <= self.width+1:
-                return True
-
-        return False
-
-    def GetName(self):
-        return self.id + ' Color:' + self.color
-
-    def ShowProperties(self, event):
-        dlg = wx.Dialog(self.canvas, wx.ID_ANY, "Circle Properties")
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        radius = wx.TextCtrl(dlg, wx.ID_ANY)
-        radius.SetValue(str(self.radius))
-
-        colorbtn = wx.Button(dlg, wx.ID_ANY, "Color")
-        colorbtn.SetForegroundColour(self.hcolor)
-
-        def ColorBtn(event):
-            newcolor = self.RGBHex.do_hex_color_dlg(self.canvas)
-            if newcolor == None:
-                return
-
-            colorbtn.SetForegroundColour(newcolor)
-            dlg.Unbind(wx.EVT_BUTTON)
-
-        dlg.Bind(wx.EVT_BUTTON, ColorBtn, colorbtn)
-
-        sizer.Add(wx.StaticText(dlg, wx.ID_ANY, "Radius:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 2)
-        sizer.Add(radius, 0, wx.EXPAND|wx.ALL, 3)
-        sizer.Add(colorbtn, 0, wx.ALL, 2)
-        sizer.Add(wx.Button(dlg, wx.ID_OK), 0, wx.ALL, 3)
-
-        dlg.SetSizer(sizer)
-        dlg.SetAutoLayout(True)
-        dlg.Fit()
-        dlg.Show()
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.radius = int(radius.GetValue())
-            r,g,b = colorbtn.GetForegroundColour().Get()
-            self.color = self.RGBHex.hexstring(r, g, b)
-            self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-            self.Update(send=True, action="update")
-
-
-    def OnLeftDown(self, pos):
-        self.lastPoint = pos
-        self.start = pos
-        self.points.append((pos.x, pos.y))
-
-    def OnMotion(self, pos):
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-
-        r,g,b = self.RGBHex.rgb_tuple(self.canvas.whiteboardColor)
-        pen = wx.Pen(wx.Color(r,g,b,255), int(self.canvas.toolWnd.LineWidth.GetStringSelection()))
-        dc.SetPen(pen)
-
-        xd = (self.lastPoint.x-pos.x)*(self.lastPoint.x-pos.x)
-        yd = (self.lastPoint.y-pos.y)*(self.lastPoint.y-pos.y)
-        distance = sqrt(xd+yd)
-
-        if distance > 5:
-            if self.canvas.toolWnd.currentLine == 'Free':
-                self.points.append((pos.x, pos.y))
-                self.lastPoint = pos
-                dc.DrawLines(self.points)
-            else:
-                dc.SetLogicalFunction(wx.INVERT)
-                dc.DrawLine(self.start.x, self.start.y, self.lastPoint.x, self.lastPoint.y)
-                dc.DrawLine(self.start.x, self.start.y, pos.x, pos.y)
-                dc.SetLogicalFunction(wx.COPY)
-                dc.DrawLines(self.points)
-                self.lastPoint = pos
-
-        dc.SetPen(wx.NullPen)
-
-    def OnLeftUp(self, pos):
-        if self.canvas.toolWnd.currentLine == 'Free' and len(self.points) > 2:
-            self.points.append((pos.x, pos.y))
-            self.canvas.zOrder['front'].append(MapLine(self.canvas, self.points[0], int(self.canvas.toolWnd.LineWidth.GetStringSelection()), self.canvas.whiteboardColor, self.points))
-            self.start = wx.Point(0,0)
-            self.points = []
-
-    def OnLeftDClick(self, pos):
-        if self.canvas.toolWnd.currentLine == 'Poly' and len(self.points) > 2:
-            self.points.append((pos.x, pos.y))
-            self.canvas.zOrder['front'].append(MapLine(self.canvas, self.points[0], int(self.canvas.toolWnd.LineWidth.GetStringSelection()), self.canvas.whiteboardColor, self.points))
-            self.points = []
-            self.start = wx.Point(0,0)
-
-    def _toxml(self, action="update"):
-        return ''
\ No newline at end of file
--- a/orpg/map/_object.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-from math import sqrt
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-from orpg.tools.rgbhex import RGBHex
-
-wxEVT_ENTER_OBJECT = wx.NewEventType()
-wxEVT_LEAVE_OBJECT = wx.NewEventType()
-wxEVT_SELECT_OBJECT = wx.NewEventType()
-wxEVT_DESELECT_OBJECT = wx.NewEventType()
-EVT_ENTER_OBJECT = wx.PyEventBinder(wxEVT_ENTER_OBJECT)
-EVT_LEAVE_OBJECT = wx.PyEventBinder(wxEVT_LEAVE_OBJECT)
-EVT_SELECT_OBJECT = wx.PyEventBinder(wxEVT_SELECT_OBJECT)
-EVT_DESELECT_OBJECT = wx.PyEventBinder(wxEVT_DESELECT_OBJECT)
-
-class ObjectEvent(wx.PyCommandEvent):
-    def __init__(self, eventType, object):
-        wx.PyCommandEvent.__init__(self, eventType)
-
-        self._object = object
-
-        self._eventType = eventType
-        self.notify = wx.NotifyEvent(eventType, -1)
-
-    def GetNotifyEvent(self):
-        return self.notify
-
-    def GetObject(self):
-        return self._object
-
-    def GetId(self):
-        return self._object.GetId()
-
-class MapObject:
-    def __init__(self, **kwargs):
-        self.id = -1
-        self.start = wx.Point(0,0)
-        self.color = "#000000"
-        self.hcolor = "#ffffff"
-        self.lineWidth = 1
-        self.zOrder = 'front'
-        self.selected = False
-        self.inObject = False
-        self.highlighed = False
-        self.isshown = True
-        self.canvas = None
-        self.RGBHex = RGBHex()
-        self.trans = 1
-
-        for atter, value in kwargs.iteritems():
-            setattr(self, atter, value)
-
-        try:
-            if self.id == wx.ID_ANY:
-                self.id = wx.NewId()
-        except:
-            self.id = wx.NewId()
-
-    #Public Methods
-    def HitTest(self, pos):
-        if self.InObject(pos) and not self.inObject and not self.selected:
-            self.inObject = True
-            evt = ObjectEvent(wxEVT_ENTER_OBJECT, self)
-            self.canvas.GetEventHandler().ProcessEvent(evt)
-        elif not self.InObject(pos) and self.inObject and not self.selected:
-            self.inObject = False
-            evt = ObjectEvent(wxEVT_LEAVE_OBJECT, self)
-            self.canvas.GetEventHandler().ProcessEvent(evt)
-
-    def GetId(self):
-        return self.id
-
-    def IsShown(self):
-        return self.isshown
-
-    def Show(self, event=None, show=True):
-        self.isshown = show
-        self.Update(send=True, action="update")
-
-    def Hide(self, event=None):
-        self.isshown = False
-        self.Update(send=True, action="update")
-
-    def IsSelected(self):
-        return self.selected
-
-    def Select(self, select=True):
-        self.selected = select
-
-        if select:
-            evt = ObjectEvent(wxEVT_SELECT_OBJECT, self)
-        else:
-            evt = ObjectEvent(wxEVT_DESELECT_OBJECT, self)
-
-        self.canvas.GetEventHandler().ProcessEvent(evt)
-
-    def Deselect(self):
-        self.selected = False
-        evt = ObjectEvent(wxEVT_DESELECT_OBJECT, self)
-        self.canvas.GetEventHandler().ProcessEvent(evt)
-
-    def Update(self, send=False, action="update"):
-        self.canvas.UpdateMap()
-        if send:
-            self.canvas.session.send(self._toxml(action))
-
-    def GetName(self):
-        return 'ID: ' + str(self.id) + ' Color: ' + self.color
-
-    def InObject(self, pos):
-        pass
-
-    def Draw(self, dc):
-        if self.selected:
-            self.DrawSelected(dc)
-
-    def DrawSelected(self, dc):
-        pass
-
-    def Highlight(self):
-        self.highlighed = True
-        self.Update()
-
-    def UnHighlight(self):
-        self.highlighed = False
-        self.Update()
-
-    def OnLeftDown(self, pos):
-        if self.inObject and self.selected:
-            self.start = pos
-            self.Deselect()
-
-        elif self.inObject and not self.selected:
-            self.Select()
-
-        else:
-            self.start = pos
-
-        self.Update()
-
-    def OnMotion(self, pos):
-        cdc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(cdc)
-        dc = wx.GraphicsContext.Create(cdc)
-
-        if self.selected:
-            self.start = pos
-            self.Draw(dc)
-
-    def OnLeftUp(self, pos):
-        pass
-
-    def OnRightDown(self, pos):
-        pass
-
-    def OnLeftDClick(self, pos):
-        pass
-
-    def ShowProperties(self, event):
-        pass
-
-    def _toxml(self, action="update"):
-        return ''
\ No newline at end of file
--- a/orpg/map/_text.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-from math import sqrt
-
-import wx
-
-import orpg.dirpath
-from orpg.orpgCore import *
-
-from _object import MapObject
-
-class MapText(MapObject):
-    def __init__(self, canvas, start=wx.Point(0,0), text='', size=12, weight=wx.NORMAL, style=wx.NORMAL, color="#000000"):
-        MapObject.__init__(self, canvas=canvas)
-        self.start = start
-        self.color = color
-        self.text = text
-        self.weight = weight
-        self.style = style
-        self.size = size
-
-        r, g, b = self.RGBHex.rgb_tuple(self.color)
-        self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-
-        self.id = 'text-' + self.canvas.GetNewObjectId()
-
-
-    def Draw(self, dc):
-        if not self.highlighed:
-            c = self.color
-        else:
-            c = self.hcolor
-
-        font = wx.Font(self.size, wx.DEFAULT, self.weight, self.style)
-        dc.SetFont(font, c)
-        w, h = dc.GetTextExtent(self.text)
-
-
-        if self.IsShown():
-            dc.DrawText(self.text, self.start.x-(w/2), self.start.y-(h/2))
-        elif self.canvas.toolWnd.gmToolBar.IsShown():
-            r, g, b = self.RGBHex.rgb_tuple(c)
-            dc.SetFont(font, wx.Color(r, g, b, 40))
-            dc.DrawText(self.text, self.start.x-(w/2), self.start.y-(h/2))
-
-
-        if self.selected:
-            self.DrawSelection(dc)
-
-    def DrawSelection(self, dc):
-        w, h = dc.GetTextExtent(self.text)
-        dc.SetBrush(wx.GREEN_BRUSH)
-        dc.SetPen(wx.GREEN_PEN)
-        path = dc.CreatePath()
-
-        path.AddRectangle(self.start.x-((w/2)+1), self.start.y-((h/2)+1), 5, 5)
-        path.AddRectangle(self.start.x-((w/2)+1), self.start.y+((h/2)+1), 5, 5)
-        path.AddRectangle(self.start.x+((w/2)+1), self.start.y-((h/2)+1), 5, 5)
-        path.AddRectangle(self.start.x+((w/2)+1), self.start.y+((h/2)+1), 5, 5)
-
-        dc.DrawPath(path)
-
-        dc.SetBrush(wx.NullBrush)
-        dc.SetPen(wx.NullPen)
-
-    def InObject(self, pos):
-        dc = wx.ClientDC(self.canvas)
-        self.canvas.PrepareDC(dc)
-        font = wx.Font(self.size, wx.DEFAULT, self.weight, self.style)
-        w, h = dc.GetTextExtent(self.text)
-        rgn = wx.RegionFromPoints([(self.start.x-(w/2), self.start.y-(h/2)), (self.start.x-(w/2), self.start.y+(h/2)), (self.start.x+(w/2), self.start.y-(h/2)), (self.start.x+(w/2), self.start.y+(h/2))])
-
-        if rgn.Contains(pos.x, pos.y):
-            return True
-
-        return False
-
-    def GetName(self):
-        return self.text + ' Color:' + self.color
-
-    def ShowProperties(self, event):
-        dlg = wx.Dialog(self.canvas, wx.ID_ANY, "Circle Properties")
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        text = wx.TextCtrl(dlg, wx.ID_ANY)
-        text.SetValue(self.text)
-
-        colorbtn = wx.Button(dlg, wx.ID_ANY, "Color")
-        colorbtn.SetForegroundColour(self.color)
-
-        size = wx.SpinCtrl(dlg, wx.ID_ANY, value=str(self.size), min=7, initial=12, name="Font Size: ")
-
-        weight = wx.Choice(dlg, wx.ID_ANY, choices=["Normal", "Bold"])
-        if self.weight == wx.NORMAL:
-            weight.SetSelection(0)
-        else:
-            weight.SetSelection(1)
-
-        style = wx.Choice(dlg, wx.ID_ANY, choices=["Normal", "Italic"])
-        if self.weight == wx.NORMAL:
-            style.SetSelection(0)
-        else:
-            style.SetSelection(1)
-
-        def ColorBtn(event):
-            newcolor = self.RGBHex.do_hex_color_dlg(self.canvas)
-            if newcolor == None:
-                return
-
-            colorbtn.SetForegroundColour(newcolor)
-            dlg.Unbind(wx.EVT_BUTTON)
-
-        dlg.Bind(wx.EVT_BUTTON, ColorBtn, colorbtn)
-
-        sizer.Add(wx.StaticText(dlg, wx.ID_ANY, "Text:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 2)
-        sizer.Add(text, 0, wx.EXPAND|wx.ALL, 3)
-        sizer.Add(size, 0, wx.ALL, 2)
-        sizer.Add(weight, 0, wx.ALL, 3)
-        sizer.Add(style, 0, wx.ALL, 2)
-        sizer.Add(colorbtn, 0, wx.ALL, 3)
-        sizer.Add(wx.Button(dlg, wx.ID_OK), 0, wx.ALL, 2)
-
-        dlg.SetSizer(sizer)
-        dlg.SetAutoLayout(True)
-        dlg.Fit()
-        dlg.Show()
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.text = text.GetValue()
-            r,g,b = colorbtn.GetForegroundColour().Get()
-            self.color = self.RGBHex.hexstring(r, g, b)
-            self.hcolor = self.RGBHex.hexstring(r^255, g^255, b^255)
-            self.size = int(size.GetValue())
-            if weight.GetSelection() == 0:
-                self.weight = wx.NORMAL
-            else:
-                self.weight = wx.BOLD
-
-            if style.GetSelection() == 0:
-                self.style = wx.NORMAL
-            else:
-                self.style = wx.ITALIC
-
-            if event != None:
-                self.Update(send=True, action="update")
-
-
-    def OnLeftDown(self, pos):
-        self.ShowProperties(None)
-        self.color = self.canvas.whiteboardColor
-        if self.text != '':
-            self.canvas.zOrder['front'].append(MapText(self.canvas, pos, self.text, self.size, self.weight, self.style, self.color))
-            self.Update(send=True, action='new')
-
-        self.text = ''
-        self.weight = wx.NORMAL
-        self.size = 12
-        self.style = wx.NORMAL
-        self.color = self.canvas.whiteboardColor
-        self.hcolor = self.canvas.whiteboardColor
-
-    def _toxml(self, action="update"):
-        return ''
\ No newline at end of file
--- a/orpg/mapper/background.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/mapper/background.py	Wed Apr 28 08:08:09 2010 -0500
@@ -34,6 +34,7 @@
 from orpg.orpgCore import component
 from orpg.tools.orpg_log import logger
 from orpg.tools.orpg_settings import settings
+from xml.etree.ElementTree import fromstring
 
 ##-----------------------------
 ## background layer
@@ -244,22 +245,21 @@
     def upload(self, postdata, filename, type):
         self.lock.acquire()
         if type == 'Image' or type == 'Texture':
-            url = component.get('settings').get_setting('ImageServerBaseURL')
+            url = settings.get_setting('ImageServerBaseURL')
             file = urllib.urlopen(url, postdata)
             recvdata = file.read()
             file.close()
             try:
-                xml_dom = minidom.parseString(recvdata)._get_documentElement()
-                if xml_dom.nodeName == 'path':
-                    path = xml_dom.getAttribute('url')
+                xml_dom = fromstring(recvdata)
+                if xml_dom.tag == 'path':
+                    path = xml_dom.get('url')
                     path = urllib.unquote(path)
                     if type == 'Image': self.set_image(path, 1)
                     else: self.set_texture(path)
                     self.localPath = filename
                     self.local = True
                     self.localTime = time.time()
-                else:
-                    print xml_dom.getAttribute('msg')
+                else: print xml_dom.get('msg')
             except Exception, e:
                 print e
                 print recvdata
--- a/orpg/mapper/map.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/mapper/map.py	Wed Apr 28 08:08:09 2010 -0500
@@ -156,7 +156,8 @@
             else: pass
         if not ImageHandler.Queue.empty():
             (path, image_type, imageId) = ImageHandler.Queue.get()
-            if path == 'failed': img = wx.Image(dir_struct["icon"] + "failed.png", wx.BITMAP_TYPE_PNG)
+            if (path == 'failed' or path == dir_struct["icon"] + "failed.png"): 
+                img = wx.Image(dir_struct["icon"] + "failed.png", wx.BITMAP_TYPE_PNG)
             else: img = wx.ImageFromMime(path[1], path[2])
             try:
                 # Now, apply the image to the proper object
@@ -250,8 +251,9 @@
         topleft1 = self.GetViewStart()
         topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]]
         if (clientsize[0] > 1) and (clientsize[1] > 1):
-            self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
-            dc = wx.AutoBufferedPaintDC(self)
+            dc = wx.MemoryDC()
+            bmp = wx.EmptyBitmap(clientsize[0]+1, clientsize[1]+1)
+            dc.SelectObject(bmp)
             dc.SetPen(wx.TRANSPARENT_PEN)
             dc.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
             dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1)
@@ -266,11 +268,22 @@
             self.layers['fog'].layerDraw(dc, topleft, clientsize)
             dc.SetPen(wx.NullPen)
             dc.SetBrush(wx.NullBrush)
+
+            dc.SelectObject(wx.NullBitmap)
+            del dc
+            wdc = self.preppaint()
+            wdc.DrawBitmap(bmp, topleft[0], topleft[1])
+
             if settings.get_setting("AlwaysShowMapScale") == "1":
-                self.showmapscale(dc)
+                self.showmapscale(wdc)
         try: evt.Skip()
         except: pass
 
+    def preppaint(self):
+        dc = wx.PaintDC(self)
+        self.PrepareDC(dc)
+        return (dc)
+
     def showmapscale(self, dc):
         scalestring = "Scale x" + `self.layers['grid'].mapscale`[:3]
         (textWidth, textHeight) = dc.GetTextExtent(scalestring)
--- a/orpg/mapper/whiteboard_handler.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/mapper/whiteboard_handler.py	Wed Apr 28 08:08:09 2010 -0500
@@ -754,9 +754,9 @@
         pos = self.get_snapped_to_logical_pos(evt)
         size = self.canvas.layers['grid'].unit_size #60
         radius = int(int(self.radius.GetValue())/5)
-        center = wx.Point(pos.x, pos.y+size*radius)
+        center = wx.Point(pos.x, pos.y)
         curve  = self.calculate_circle(center, radius, size)
-        if(self.temp_circle):
+        if self.temp_circle:
             self.canvas.layers['whiteboard'].del_temp_line(self.temp_circle)
             self.selected = None
         self.temp_circle = self.canvas.layers['whiteboard'].add_temp_line(curve)
--- a/orpg/networking/meta_server_lib.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/networking/meta_server_lib.py	Wed Apr 28 08:08:09 2010 -0500
@@ -312,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")
@@ -323,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_server.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/networking/mplay_server.py	Wed Apr 28 08:08:09 2010 -0500
@@ -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/traipse-openrpg'>"
+            lobbyMsg += DISTRO +'</a> '+ DIS_VER +' {'+ BUILD+'}'
+            lobbyMsg += " server, built on OpenRPG version '" + VERSION + "'"
 
             # See if we have a server name to report!
             if len(self.serverName): lobbyMsg += ", named '" + self.serverName + "'."
@@ -1250,7 +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)
@@ -1394,13 +1396,16 @@
         self.incoming_event.set()
 
     def parse_incoming_dom(self, data):
-        end = data.find(">") #locate end of first element of message
+        end = data.find(">")
         head = data[:end+1]
-        xml_dom = None
+        msg = data[end+1:]
+        ### This if statement should help close invalid messages. ###
+        if head[end:] != '/':
+            if head[end:] != '>': head = head[:end] + '/>'
         try:
-            xml_dom = XML(head)
+            try: xml_dom = fromstring(head)
+            except: xml_dom = fromstring(head[:end] +'/>')
             self.message_action(xml_dom, data)
-
         except Exception, e:
             print "Error in parse of inbound message. Ignoring message."
             print "  Offending data(" + str(len(data)) + "bytes)=" + data
@@ -1603,6 +1608,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 +1638,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"
@@ -2184,10 +2190,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	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/networking/mplay_server_gui.py	Wed Apr 28 08:08:09 2010 -0500
@@ -151,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))
@@ -162,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):
@@ -354,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 = ""
@@ -401,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)
@@ -412,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)
@@ -437,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
@@ -522,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
@@ -545,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 ):
@@ -569,13 +573,16 @@
             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()
             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()
@@ -584,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")
 
@@ -598,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):
@@ -613,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()
@@ -627,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	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/orpg_version.py	Wed Apr 28 08:08:09 2010 -0500
@@ -2,9 +2,9 @@
 SERVER_MIN_CLIENT_VERSION = "1.7.1"
 
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
-DISTRO = "Traipse Beta"
+DISTRO = "Traipse Alpha"
 DIS_VER = "Ornery Orc"
-BUILD = "100201-03"
+BUILD = "100428-03"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/templates/default_settings.xml	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/templates/default_settings.xml	Wed Apr 28 08:08:09 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/metaservers.cache	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/templates/metaservers.cache	Wed Apr 28 08:08:09 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/split.xml	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/templates/nodes/split.xml	Wed Apr 28 08:08:09 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	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/templates/nodes/textctrl.xml	Wed Apr 28 08:08:09 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/tools/InterParse.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/tools/InterParse.py	Wed Apr 28 08:08:09 2010 -0500
@@ -1,35 +1,75 @@
+#!/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
+from xml.etree.ElementTree import iselement
 
 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 Post(self, s, tab=False, send=False, myself=False):
+        if not tab: tab = component.get('chat')
+        s = self.Normalize(s, tab)
+        tab.set_colors()
+        tab.Post(s, send, myself)
 
-    def Normalize(self, s):
-        for plugin_fname in component.get('chat').activeplugins.keys():
-            plugin = component.get('chat').activeplugins[plugin_fname]
+    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, tab):
+        for plugin_fname in tab.activeplugins.keys():
+            plugin = tab.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(traceback.format_exc())
                     logger.general("EXCEPTION: " + str(e))
-        if component.get('chat').parsed == 0:
+        if tab.parsed == 0:
+            s = self.NameSpaceE(s)
             s = self.Node(s)
             s = self.Dice(s)
-            s = self.Filter(s)
-            component.get('chat').parsed = 1
+            s = self.Filter(s, tab)
+            tab.parsed = 1
         return s
     
-    def Filter(self, s):
-        s = component.get('chat').GetFilteredText(s)
+    def Filter(self, s, tab):
+        s = tab.GetFilteredText(s)
         return s
 
     def Node(self, s):
@@ -77,7 +117,7 @@
             lb = "Replace '?' with: "
             if len(matches[i][0]):
                 lb = matches[i][1] + "?: "
-            dlg = TextEntryDialog(self, lb, "Missing Value?")
+            dlg = TextEntryDialog(component.get('chat'), lb, "Missing Value?")
             dlg.SetValue('')
             if matches[i][0] != '':
                 dlg.SetTitle("Enter Value for " + matches[i][1])
@@ -87,6 +127,90 @@
             dlg.Destroy()
         return s
 
+    def LocationCheck(self, node, tree_map, new_map, find):
+        if node == 'Invalid Reference!': return node
+        namespace = node.getiterator('nodehandler'); tr = tree_map.split('::')
+        newstr = ''
+        for name in namespace:
+            try: t = new_map.index(name.get('name'))-1
+            except: t = 0
+            if find[0] == name.get('name'):
+                s = '::'.join(new_map[:len(tr)-t])+'::'+'::'.join(find)
+                newstr = self.NameSpaceE('!&' +s+ '&!')
+                break
+        if newstr != '': return newstr
+        else:
+            del new_map[len(new_map)-1]
+            node = self.get_node(new_map)
+            newstr = self.LocationCheck(node, tree_map, new_map, find)
+            return newstr
+
+    def FutureCheck(self, node, next):
+        future = node.getiterator('nodehandler')
+        for advance in future:
+            if next == advance.get('name'): return True
+        return False
+
+    def NameSpaceI(self, s, node):
+        reg = re.compile("(!=(.*?)=!)")
+        matches = reg.findall(s)
+        tree_map = node.get('map')
+        for i in xrange(0,len(matches)):
+            ## Build the new tree_map
+            new_map = tree_map.split('::')
+            find = matches[i][1].split('::')
+            ## Backwards Reference the Parent Children
+            node = self.get_node(new_map)
+            newstr = self.LocationCheck(node, tree_map, new_map, find)
+            s = s.replace(matches[i][0], newstr, 1)
+        return s
+
+    def NameSpaceE(self, s):
+        reg = re.compile("(!&(.*?)&!)")
+        matches = reg.findall(s)
+        newstr = False
+        nodeable = ['rpg_grid_handler', 'container_handler', 
+                    'group_handler', 'tabber_handler', 
+                    'splitter_handler', 'form_handler', 'textctrl_handler']
+        for i in xrange(0,len(matches)):
+            find = matches[i][1].split('::')
+            node = component.get('tree').xml_root
+            if not iselement(node): 
+                s = s.replace(matches[i][0], 'Invalid Reference!', 1); 
+                s = self.NameSpaceE(s)
+                return s
+            for x in xrange(0, len(find)):
+                namespace = node.getiterator('nodehandler')
+                for node in namespace:
+                    if find[x] == node.get('name'):
+                        if node.get('class') not in nodeable: continue
+                        if node.get('class') == 'rpg_grid_handler':
+                            try: newstr = self.NameSpaceGrid(find[x+1], node); break
+                            except: newstr = 'Invalid Grid Reference!'
+                        try:
+                            if self.FutureCheck(node, find[x+1]): break
+                            else: continue
+                        except:
+                            if x == len(find)-1:
+                                if node.find('text') != None: newstr = str(node.find('text').text) 
+                                else: newstr = 'Invalid Reference!'
+                                break
+                            else: break
+            if not newstr: newstr = 'Invalid Reference!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.ParseLogic(s, node)
+        return s
+
+    def NameSpaceGrid(self, s, node):
+        cell = tuple(s.strip('(').strip(')').split(','))
+        grid = node.find('grid')
+        rows = grid.findall('row')
+        try:
+            col = rows[int(self.Dice(cell[0]))-1].findall('cell')
+            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
@@ -112,7 +236,7 @@
             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))
+            child_node = self.get_node(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)
@@ -130,14 +254,13 @@
         if newstr != '': return newstr
         else:
             del new_map[len(new_map)-1]
-            child_node = self.get_node('::'.join(new_map))
+            child_node = self.get_node(new_map)
             newstr = self.get_root(child_node, tree_map, new_map, parent_map)
             return newstr
 
-    def get_node(self, s):
+    def get_node(self, path):
         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
@@ -147,7 +270,7 @@
     def resolve_get_loop(self, node, path, step, depth):
         if step == depth: return node
         else:
-            child_list = node.findall('nodehandler')
+            child_list = node.getchildren()
             for child in child_list:
                 if step == depth: break
                 if child.get('name') == path[step]:
@@ -195,10 +318,8 @@
             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.NodeMap(s, node)
-        s = self.NodeParent(s, node.get('map'))
+        else: s = ''
+        s = self.ParseLogic(s, node)
         return s
 
     def resolve_grid(self, node, path, step, depth):
@@ -208,7 +329,7 @@
         grid = node.find('grid')
         rows = grid.findall('row')
         col = rows[int(self.Dice(cell[0]))-1].findall('cell')
-        try: s = self.NodeMap(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
+        try: s = self.ParseLogic(col[int(self.Dice(cell[1]))-1].text, node) or 'No Cell Data'
         except: s = 'Invalid Grid Reference!'
         return s
 
--- a/orpg/tools/aliaslib.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/tools/aliaslib.py	Wed Apr 28 08:08:09 2010 -0500
@@ -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):
@@ -458,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;", "'")
@@ -495,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'
@@ -503,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)
 
--- a/orpg/tools/orpg_log.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/tools/orpg_log.py	Wed Apr 28 08:08:09 2010 -0500
@@ -62,7 +62,7 @@
     def write(self, text):
         logger.stdout(text)
         wx.Yield()
-        #sys.__stdout__.write(text)
+        sys.__stdout__.write(text)
 
 class TrueDebug(object):
     """A simple debugger. Add debug() to a function and it prints the function name and any objects included. Add an object or a group of objects in ()'s.
--- a/orpg/tools/orpg_settings.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/orpg/tools/orpg_settings.py	Wed Apr 28 08:08:09 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/plugins/xxurl2link.py	Mon Feb 01 18:29:16 2010 -0600
+++ b/plugins/xxurl2link.py	Wed Apr 28 08:08:09 2010 -0500
@@ -9,36 +9,36 @@
     def __init__(self, plugindb, parent):
         orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
 
-        # The Following code should be edited to contain the proper information
         self.name = 'URL to link conversion'
         self.author = 'tdb30 tbaleno@wrathof.com'
         self.help = "This plugin automaticaly wraps urls in link tags\n"
         self.help += "making them clickable."
 
-        self.url_regex = None
-        self.mailto_regex = None
-
     def plugin_menu(self):
         self.menu = wx.Menu()
         self.toggle = self.menu.AppendCheckItem(wx.ID_ANY, 'On')
         self.topframe.Bind(wx.EVT_MENU, self.plugin_toggle, self.toggle)
-        self.toggle.Check(True)
 
     def plugin_toggle(self, evt):
+        if self.toggle.IsChecked() == True: self.plugindb.SetString('xxurl2link', 'url2link', 'True')
+        if self.toggle.IsChecked() == False: self.plugindb.SetString('xxurl2link', 'url2link', 'False')
         pass
 
     def plugin_enabled(self):
-        #This is where you set any variables that need to be initalized when your plugin starts
-        self.url_regex = re.compile("(?<![\[=\"a-z0-9:/.])((?:http|ftp|gopher)://)?(?<![@a-z])((?:[a-z0-9\-]+[-.]?[a-z0-9]+)*\.(?:[a-z]{2,4})(?:[a-z0-9_=\?\#\&~\%\.\-/\:\+;]*))", re.I)
-
-        self.mailto_regex = re.compile("(?<![=\"a-z0-9:/.])((?:[a-z0-9]+[_]?[a-z0-9]*)+@{1}(?:[a-z0-9]+[-.]?[a-z0-9]+)*\.(?:[a-z]{2,4}))", re.I)
+        self.url_regex = re.compile( #from Paul Hayman of geekzilla
+                    "((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.I)
+        self.mailto_regex = re.compile( #Taken from Django
+                    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
+                    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
+                    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)
+        self.link = self.plugindb.GetString('xxurl2link', 'url2link', '') or 'False'
+        self.toggle.Check(True) if self.link == 'True' else self.toggle.Check(False)
 
     def plugin_disabled(self):
-        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
-        #such as closing windows created by the plugin
         pass
 
     def pre_parse(self, text):
+        text2 = text
         if self.toggle.IsChecked() == True:
             text = self.mailto_regex.sub(self.regmailsub, text)
             text = self.url_regex.sub(self.regurlsub, text)
@@ -56,7 +56,5 @@
 
     def regurlsub(self, m):
         link = m.group(2)
-        if m.group(1) != None:
-            return '<a href="' + m.group(1).lower() + link + '">' + m.group(0) + '</a>'
-        else:
-            return '<a href="http://' + link + '">' + link + '</a>'
+        if m.group(1) != None: return '<a href="' + m.group(1).lower() + '">' + m.group(0) + '</a>'
+        else: return '<a href="http://' + link + '">' + link + '</a>'
--- a/readme.txt	Mon Feb 01 18:29:16 2010 -0600
+++ b/readme.txt	Wed Apr 28 08:08:09 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/rollback.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-
-HG = os.environ["HG"]
-
-os.system(HG + " rollback")
-os.system(HG + " revert --all")
-print "Since you reverted, I am guessing there are issues with the last update"
-print "PLEASE notify me on either the openrpg.com boards, or by email"
-print "digitalxero@gmail.com"
-print "You can continue using your rolled back version by launching openrpg from"
-print "the command line with the command: OpenRPG*.py -n"
-print "the -n tells the system not to update, it will still run the downloader"
-print "but it will not change your files"
-raw_input("press <enter> key to terminate program")
\ No newline at end of file
--- a/start_developer.py	Mon Feb 01 18:29:16 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/start_noupdate.py	Mon Feb 01 18:29:16 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/start_tester.py	Mon Feb 01 18:29:16 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-
-HG = os.environ["HG"]
-
-import pyver
-pyver.checkPyVersion()
-
-from orpg.orpg_wx import *
-import upmana.updatemana
-app = upmana.updatemana.updateApp(0)
-app.MainLoop()
-for key in sys.modules.keys():
-    if 'orpg' in key:
-        del sys.modules[key]
-
-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	Mon Feb 01 18:29:16 2010 -0600
+++ b/upmana/updatemana.py	Wed Apr 28 08:08:09 2010 -0500
@@ -12,8 +12,9 @@
 class Term2Win(object):
     # A stdout redirector.  Allows the messages from Mercurial to be seen in the Install Window
     def write(self, text):
-        statbar.SetStatusText(text)
-        wx.Yield()
+        self.closed = sys.__stdout__.closed
+        self.flush = sys.__stdout__.flush
+        statbar.SetStatusText(text.replace('\n', ''))
         sys.__stdout__.write(text)
 
 class Updater(wx.Panel):
@@ -21,7 +22,10 @@
         wx.Panel.__init__(self, parent)
         ### Status Bar ###
         #statbar.SetStatusText('Select a Package and Update')
-        statbar.SetStatusText('New Status Bar')
+        #statbar.SetStatusText('New Status Bar')
+
+        self.timer = wx.Timer(self, 1)
+        self.count = 0
 
         ### Update Manager
         self.ui = ui.ui()
@@ -44,7 +48,7 @@
         self.buttons['update'] = wx.Button(self, wx.ID_ANY, "Update Now")
         self.buttons['finish'] = wx.Button(self, wx.ID_ANY, "Finish")
 
-        self.sizer.Add(self.changelog, (0,0), span=(4,1), flag=wx.EXPAND)
+        self.sizer.Add(self.changelog, (0,0), span=(5,1), flag=wx.EXPAND)
         self.sizer.Add(self.filelist, (0,1), span=(1,3), flag=wx.EXPAND)
 
         self.sizer.Add(self.buttons['progress_bar'], (1,1), span=(1,3), flag=wx.EXPAND)
@@ -55,7 +59,7 @@
         self.sizer.Add(self.buttons['advanced'], (2,3), flag=wx.EXPAND)
         self.sizer.Add(self.buttons['update'], (3,3), flag=wx.EXPAND)
         self.sizer.Add(self.buttons['finish'], (4,3), flag=wx.EXPAND)
-        #self.buttons['finish'].Disable()
+        self.buttons['progress_bar'].SetValue(100)
         self.sizer.AddGrowableCol(0)
         self.sizer.AddGrowableRow(0)
         self.SetSizer(self.sizer)
@@ -76,6 +80,29 @@
         self.Bind(wx.EVT_BUTTON, self.ChooseBranch, self.buttons['advanced'])
         self.Bind(wx.EVT_CHECKBOX, self.ToggleAutoUpdate, self.buttons['auto_check'])
         self.Bind(wx.EVT_CHECKBOX, self.ToggleNoUpdate, self.buttons['no_check'])
+        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
+
+    def OnTimer(self, event):
+        self.count = self.count + 1
+        self.buttons['progress_bar'].SetValue(self.count)
+        if self.count == 100:
+            self.timer.Stop()
+            statbar.SetStatusText('Checking For Updates')
+
+    def UpdateCheck(self):
+        self.timer.Start(100)
+        self.count = 3
+        self.buttons['progress_bar'].SetValue(3)
+        doUpdate = commands.incoming(self.ui, self.repo, 
+                    manifest.GetString('default', 'repo', ''), force=True, bundle=False)
+        if doUpdate:
+            statbar.SetStatusText('No Updates Available')
+            self.buttons['progress_bar'].SetValue(100)
+            self.timer.Stop()
+        else:
+            statbar.SetStatusText('Refresh Repo For Updated Source')
+            self.buttons['progress_bar'].SetValue(100)
+            self.timer.Stop()
 
     def ToggleAutoUpdate(self, event):
         if self.buttons['auto_check'].GetValue() == True:
@@ -687,17 +714,18 @@
 
         global statbar
         statbar = self.CreateStatusBar()
+        sys.stdout = Term2Win()
         self.Centre()
 
         # create the page windows as children of the notebook
-        page1 = Updater(nb, openrpg)
+        self.page1 = Updater(nb, openrpg)
         page2 = Repos(nb, openrpg)
         page3 = Manifest(nb)
         page4 = Control(nb)
         page5 = Help(nb)
 
         # add the pages to the notebook with the label to show on the tab
-        nb.AddPage(page1, "Updater")
+        nb.AddPage(self.page1, "Updater")
         nb.AddPage(page2, "Repos")
         nb.AddPage(page3, "Manifest")
         nb.AddPage(page4, "Control")
@@ -720,11 +748,11 @@
 class updateApp(wx.App):
     def OnInit(self):
         self.main = False
-        sys.stdout = Term2Win()
+
         logger._set_log_to_console(False)
         logger.note("Updater Start")
         component.add('validate', validate)
-        self.updater = updaterFrame(self, "OpenRPG Update Manager 1.0", 
+        self.updater = updaterFrame(self, "OpenRPG Update Manager 1.2", 
                                 component, manifest, self.main)
         if manifest.GetString("updatemana", "auto_update", "") == 'on' and self.main == False:
             self.AutoUpdate(); self.OnExit()
@@ -736,6 +764,7 @@
             self.updater.Show()
             self.updater.Fit()
         except: pass
+        if not self.main: self.updater.page1.UpdateCheck()
         return True
 
     def AutoUpdate(self):