changeset 183:0d9b746b5751 beta

Traipse Beta 'OpenRPG' {100115-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Beta) New Features: Added Bookmarks Added 'boot' command to remote admin Added confirmation window for sent nodes Minor changes to allow for portability to an OpenSUSE linux OS Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Zoom Mouse plugin added Images added to Plugin UI Switching to Element Tree Map efficiency, from FlexiRPG Added Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) Portable Mercurial Tip of the Day added, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Parent Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added Dieroller structure from Core New DieRoller portability for odd Dice Added 7th Sea die roller; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added Added new vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Included for Mythos roller also New Warhammer FRPG Die Roller (Special thanks to Puu-san for the support) New EZ_Tree Reference system. Push a button, Traipse the tree, get a reference (Beta!) Fixes: Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fix to Whiteboard ID to prevent random line or text deleting. Fixes to Server, Remote Server, and Server GUI Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and now reactive settings when Ok is pressed Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of a Splice Fix to Use panel of Forms and Tabbers. Now longer enters design mode Fix made Image Fetching. New fetching image and new failed image Modified ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml
author sirebral
date Fri, 15 Jan 2010 23:01:42 -0600
parents 8834425a85b0
children dcae32e219f1
files images/Copyright Notice.txt images/failed.png images/fetching.png orpg/chat/chatwnd.py orpg/dieroller/base.py orpg/dieroller/rollers/7sea.py orpg/dieroller/rollers/mythos.py orpg/dieroller/rollers/wfrpg.py orpg/dieroller/rollers/wod.py orpg/dieroller/utils.py orpg/gametree/gametree.py orpg/gametree/nodehandlers/containers.py orpg/gametree/nodehandlers/core.py orpg/gametree/nodehandlers/forms.py orpg/gametree/nodehandlers/rpg_grid.py orpg/main.py orpg/mapper/images.py orpg/mapper/map.py orpg/mapper/miniatures_handler.py orpg/networking/mplay_server.py orpg/orpgCore.py orpg/orpg_version.py orpg/templates/default_Lobby_map.xml orpg/templates/feature.xml orpg/templates/nodes/4e_char_sheet.xml orpg/templates/nodes/die_roller_notes.xml orpg/tools/orpg_settings.py orpg/tools/predTextCtrl.py plugins/xxminiquicknote.py upmana/updatemana.py
diffstat 30 files changed, 1253 insertions(+), 477 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/images/Copyright Notice.txt	Fri Jan 15 23:01:42 2010 -0600
@@ -0,0 +1,8 @@
+The following images are Copyright Sekkyumu and released to the Public Domain
+add.png
+add_button.png
+check_button.png
+(from) failed.png
+(from) fetching.png
+spotlight.png
+star.png
Binary file images/failed.png has changed
Binary file images/fetching.png has changed
--- a/orpg/chat/chatwnd.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/chat/chatwnd.py	Fri Jan 15 23:01:42 2010 -0600
@@ -168,7 +168,6 @@
         self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item)
         self.menu.AppendItem(item)
 
-    
     def OnM_EditCopy(self, evt):
         wx.TheClipboard.UsePrimarySelection(False)
         wx.TheClipboard.Open()
@@ -524,6 +523,12 @@
         self.lockscroll = False      # set the default to scrolling on.
         self.chat_cmds = commands.chat_commands(self)
         self.html_strip = strip_html
+        self.f_keys = {wx.WXK_F1: 'event.GetKeyCode() == wx.WXK_F1', wx.WXK_F2: 'event.GetKeyCode() == wx.WXK_F2', 
+                    wx.WXK_F3: 'event.GetKeyCode() == wx.WXK_F3', wx.WXK_F4: 'event.GetKeyCode() == wx.WXK_F4', 
+                    wx.WXK_F5: 'event.GetKeyCode() == wx.WXK_F5', wx.WXK_F6: 'event.GetKeyCode() == wx.WXK_F6', 
+                    wx.WXK_F7: 'event.GetKeyCode() == wx.WXK_F7', wx.WXK_F8: 'event.GetKeyCode() == wx.WXK_F8', 
+                    wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10', 
+                    wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'}
         #Alias Lib stuff
         self.defaultAliasName = 'Use Real Name'
         self.defaultFilterName = 'No Filter'
@@ -831,6 +836,7 @@
         self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock)
         self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel)
         self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar)
+        self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down)
         self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy)
     # def build_ctrls - end
 
@@ -1092,50 +1098,47 @@
     #
     # Note:  self.chattxt now handles it's own Key events.  It does, however still
     #        call it's parent's (self) OnChar to handle "default" behavior.
+
+    def submit_chat_text(self, s):
+        self.histidx = -1
+        self.temptext = ""
+        self.history = [s] + self.history 
+        #if not len(macroText): self.chattxt.SetValue("")
+
+        # play sound
+        sound_file = self.settings.get_setting("SendSound")
+        if sound_file != '': component.get('sound').play(sound_file)
+        if s[0] != "/": ## it's not a slash command
+            s = self.ParsePost( s, True, True )
+        else: self.chat_cmds.docmd(s) # emote is in chatutils.py
+
+    def on_chat_key_down(self, event):
+        s = self.chattxt.GetValue()
+        if event.GetKeyCode() == wx.WXK_RETURN and not event.ShiftDown():
+            logger.debug("event.GetKeyCode() == wx.WXK_RETURN")
+            self.set_colors()
+            if self.session.get_status() == MPLAY_CONNECTED:
+                self.sendTyping(0)
+            if len(s):
+                self.chattxt.SetValue('')
+                s = s.replace('\n', '<br />')
+                self.submit_chat_text(s)
+            return
+        event.Skip()
     
     def OnChar(self, event):
         s = self.chattxt.GetValue()
-        #self.histlen = len(self.history) - 1
 
-        ## RETURN KEY (no matter if there is text in chattxt)
-        #  This section is run even if there is nothing in the chattxt (as opposed to the next wx.WXK_RETURN handler
-        if event.GetKeyCode() == wx.WXK_RETURN:
-            logger.debug("event.GetKeyCode() == wx.WXK_RETURN")
-            self.set_colors()
-            if self.session.get_status() == MPLAY_CONNECTED:          #  only do if we're connected
-                self.sendTyping(0)                                    #  Send a "not_typing" event on enter key press
-        macroText=""
-        recycle_bin = {wx.WXK_F1: 'event.GetKeyCode() == wx.WXK_F1', wx.WXK_F2: 'event.GetKeyCode() == wx.WXK_F2', 
-                    wx.WXK_F3: 'event.GetKeyCode() == wx.WXK_F3', wx.WXK_F4: 'event.GetKeyCode() == wx.WXK_F4', 
-                    wx.WXK_F5: 'event.GetKeyCode() == wx.WXK_F5', wx.WXK_F6: 'event.GetKeyCode() == wx.WXK_F6', 
-                    wx.WXK_F7: 'event.GetKeyCode() == wx.WXK_F7', wx.WXK_F8: 'event.GetKeyCode() == wx.WXK_F8', 
-                    wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10', 
-                    wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'}
+        macroText = ""
+        s_key = False
+        if self.f_keys.has_key(event.GetKeyCode()): s_key = self.f_keys[event.GetKeyCode()]
 
-        bin_event = event.GetKeyCode()
-        if recycle_bin.has_key(bin_event):
-	    logger.debug(lambda bin_event: recycle_bin[bin_event])
-	    macroText = self.settings.get_setting(recycle_bin[bin_event][29:])
-	    recycle_bin = {}; del bin_event
+        if s_key: macroText = settings.get(s_key[29:])
 
         # Append to the existing typed text as needed and make sure the status doesn't change back.
         if len(macroText):
             self.sendTyping(0)
-            s = macroText
-
-        ## RETURN KEY (and not text in control)
-        if (event.GetKeyCode() == wx.WXK_RETURN and len(s)) or len(macroText):
-            logger.debug("(event.GetKeyCode() == wx.WXK_RETURN and len(s)) or len(macroText)")
-            self.histidx = -1
-            self.temptext = ""
-            self.history = [s] + self.history#prepended instead of appended now, so higher index = greater age
-            if not len(macroText): self.chattxt.SetValue("")
-            # play sound
-            sound_file = self.settings.get_setting("SendSound")
-            if sound_file != '': component.get('sound').play(sound_file)
-            if s[0] != "/": ## it's not a slash command
-                s = self.ParsePost( s, True, True )
-            else: self.chat_cmds.docmd(s) # emote is in chatutils.py
+            self.submit_chat_text(macroText)
 
         ## UP KEY
         elif event.GetKeyCode() == wx.WXK_UP:
@@ -1228,6 +1231,14 @@
                 self.Post()
             event.Skip()
 
+        elif event.GetKeyCode() == wx.WXK_RETURN and event.ShiftDown():
+            st = self.chattxt.GetValue().split('\x0b')
+            st += '\n'
+            i = self.chattxt.GetInsertionPoint()
+            self.chattxt.SetValue(''.join(st))
+            self.chattxt.SetInsertionPoint(i+1)
+            return
+
         ## NOTHING
         else: event.Skip()
         logger.debug("Exit chat_panel->OnChar(self, event)")
@@ -1860,7 +1871,7 @@
 
     def resolve_loop(self, node, path, step, depth):
         if step == depth:
-            self.resolution(node)
+            return self.resolution(node)
         else:
             child_list = node.findall('nodehandler')
             for child in child_list:
@@ -1868,11 +1879,13 @@
                 if child.get('name') == path[step]:
                     node = child
                     step += 1
-                    if node.get('class') in ('dnd35char_handler', "SWd20char_handler", "d20char_handler", "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth)
+                    if node.get('class') in ('dnd35char_handler', 
+                                            "SWd20char_handler", 
+                                            "d20char_handler", 
+                                            "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth)
                     elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth)
                     else: self.resolve_loop(node, path, step, depth)
 
-
     def resolve_grid(self, node, path, step, depth):
         if step == depth:
             self.data = 'Invalid Grid Reference!'
@@ -1885,6 +1898,71 @@
         except: self.data = 'Invalid Grid Reference!'
         return
 
+    def resolution(self, node):
+        if self.passed == False:
+            self.passed = True
+            if node.get('class') == 'textctrl_handler': 
+                s = str(node.find('text').text)
+            else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
+        else:
+            s = ''
+        s = self.ParseMap(s, node)
+        s = self.ParseParent(s, node.get('map'))
+        self.data = s
+
+    def ParseMap(self, s, node):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        reg = re.compile("(!!(.*?)!!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            tree_map = node.get('map')
+            tree_map = tree_map + '::' + matches[i][1]
+            newstr = '!@'+ tree_map +'@!'
+            s = s.replace(matches[i][0], newstr, 1)
+            s = self.ParseNode(s)
+            s = self.ParseParent(s, tree_map)
+        return s
+
+    def ParseParent(self, s, tree_map):
+        """Parses player input for embedded nodes rolls"""
+        cur_loc = 0
+        reg = re.compile("(!#(.*?)#!)")
+        matches = reg.findall(s)
+        for i in xrange(0,len(matches)):
+            ## Build the new tree_map
+            new_map = tree_map.split('::')
+            del new_map[len(new_map)-1]
+            parent_map = matches[i][1].split('::')
+            ## Find an index or use 1 for ease of use.
+            try: index = new_map.index(parent_map[0])
+            except: index = 1
+            ## Just replace the old tree_map from the index.
+            new_map[index:len(new_map)] = parent_map
+            newstr = '::'.join(new_map)
+            newstr = '!@'+ newstr +'@!'
+            s = s.replace(matches[i][0], newstr, 1)
+            #s = self.ParseMap(s, node) ## Needs to be added
+            s = self.ParseNode(s)
+        return s
+
+    def resolve_nodes(self, s):
+        self.passed = False
+        self.data = 'Invalid Reference!'
+        value = ""
+        path = s.split('::')
+        depth = len(path)
+        self.gametree = component.get('tree')
+        try: node = self.gametree.tree_map[path[0]]['node']
+        except Exception, e: return self.data
+        if node.get('class') in ('dnd35char_handler', 
+                                "SWd20char_handler", 
+                                "d20char_handler", 
+                                "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
+        elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
+        else: self.resolve_loop(node, path, 1, depth)
+        return self.data
+
     def resolve_cust_loop(self, node, path, step, depth):
         node_class = node.get('class')
         ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
@@ -1906,7 +1984,7 @@
         else: ab = node.find('saves')
         ab_list = ab.findall('save')
         for save in ab_list:
-            pc_stats[save.get('name')] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
+            pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
             if save.get('name') == 'Fortitude': abbr = 'Fort'
             if save.get('name') == 'Reflex': abbr = 'Ref'
             if save.get('name') == 'Will': abbr = 'Will'
@@ -1967,61 +2045,3 @@
             elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1]
             elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
             return
-
-    def resolution(self, node):
-        if self.passed == False:
-            self.passed = True
-            if node.get('class') == 'textctrl_handler': self.data = str(node.find('text').text)
-            else: self.data = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
-        else:
-            self.data = ''
-            pass
-        self.data = self.ParseMap(self.data, node)
-
-    def ParseMap(self, s, node):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!!(.*?)!!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            tree_map = node.get('map') + '::' + matches[i][1]
-            newstr = '!@'+ tree_map +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            s = self.ParseNode(s)
-            s = self.ParseParent(s, tree_map)
-        return s
-
-    def ParseParent(self, s, tree_map):
-        """Parses player input for embedded nodes rolls"""
-        cur_loc = 0
-        reg = re.compile("(!#(.*?)#!)")
-        matches = reg.findall(s)
-        for i in xrange(0,len(matches)):
-            ## Build the new tree_map
-            new_map = tree_map.split('::')
-            del new_map[len(new_map)-1]
-            parent_map = matches[i][1].split('::')
-            ## Find an index or use 1 for ease of use.
-            try: index = new_map.index(parent_map[0])
-            except: index = 1
-            ## Just replace the old tree_map from the index.
-            new_map[index:len(new_map)] = parent_map
-            newstr = '::'.join(new_map)
-            newstr = '!@'+ newstr +'@!'
-            s = s.replace(matches[i][0], newstr, 1)
-            s = self.ParseNode(s)
-        return s
-
-    def resolve_nodes(self, s):
-        self.passed = False
-        self.data = 'Invalid Reference!'
-        value = ""
-        path = s.split('::')
-        depth = len(path)
-        self.gametree = component.get('tree')
-        try: node = self.gametree.tree_map[path[0]]['node']
-        except: return self.data
-        if node.get('class') in ('dnd35char_handler', "SWd20char_handler", "d20char_handler", "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
-        elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
-        else: self.resolve_loop(node, path, 1, depth)
-        return self.data
--- a/orpg/dieroller/base.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/dieroller/base.py	Fri Jan 15 23:01:42 2010 -0600
@@ -392,8 +392,8 @@
 
     def __cmp__(self,other):
         #  this function included for backwards compatibility
-#  As of 2.1, lists implement the "rich comparison"
-#  methods overloaded above.
+        #  As of 2.1, lists implement the "rich comparison"
+        #  methods overloaded above.
         if type(other) == type(3) or type(other) == type(3.0):
             return cmp(self.value, other)
         elif hasattr(other,"value"):
@@ -462,4 +462,4 @@
     def __setitem__(self, *args):
         raise AttributeError
 
-die_rollers = DieRollers()
\ No newline at end of file
+die_rollers = DieRollers()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/7sea.py	Fri Jan 15 23:01:42 2010 -0600
@@ -0,0 +1,54 @@
+## 7th Sea Dieroller
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: wod.py
+# Author: OpenRPG Dev Team
+# Maintainer:
+# Version:
+#   $Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $
+#
+# Description: WOD die roller
+#
+# Targetthr is the Threshhold target
+# for compatibility with Mage die rolls.
+# Threshhold addition by robert t childers
+
+__version__ = "$Id: wod.py,v 1.14 2007/05/09 19:57:00 digitalxero Exp $"
+
+from std import std
+from orpg.dieroller.base import *
+
+class seventhsea(std):
+    name = "7sea"
+
+    def __init__(self,source=[]):
+        std.__init__(self,source)
+
+    def non_stdDie(self, s):
+        print '7th Sea'
+        num_sides = s.split('k')
+        if len(num_sides) > 1: 
+            num_sides; num = num_sides[0]; sides = '10'; target = num_sides[1]
+            ret = ['(', num.strip(), "**die_rollers['7sea'](",
+                    sides.strip(), ')).takeHighest(', target, ').open(10)']
+            s = ''.join(ret); return str(eval(s))
+
+die_rollers.register(seventhsea)
--- a/orpg/dieroller/rollers/mythos.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/dieroller/rollers/mythos.py	Fri Jan 15 23:01:42 2010 -0600
@@ -39,6 +39,7 @@
 
 class mythos(std):
     name = "mythos"
+
     def __init__(self,source=[],target=0,targetthr=0):
         std.__init__(self,source)
         self.target = target
@@ -52,12 +53,10 @@
         if target == 5: self.targets = [6, 12]
         return self
 
-    
     def thr(self,targetthr):
         self.targetthr = targetthr
         return self
 
-    
     def sum(self):
         rolls = []
         s = 0
@@ -75,7 +74,6 @@
             if botch == 1 and s < 0: s = 0
         return s
 
-    
     def __str__(self):
         if len(self.data) > 0:
             myStr = "[" + str(self.data[0])
@@ -87,4 +85,13 @@
             else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
         return myStr
 
+    def non_stdDie(self, s): ## Puu-san
+        num_sides = s.split('v')
+        if len(num_sides) > 1: 
+            num_sides; num = num_sides[0]; sides = num_sides[1]
+            sides = '10'; target = num_sides[1]
+            ret = ['(', num.strip(), "**die_rollers['mythos'](",
+                    sides.strip(), ')).vs(', target, ')']
+            return ''.join(ret)
+
 die_rollers.register(mythos)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/dieroller/rollers/wfrpg.py	Fri Jan 15 23:01:42 2010 -0600
@@ -0,0 +1,160 @@
+## a die roller as used by Warhammer Fantasy Roleplay Dice Roller
+#!/usr/bin/env python
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#       openrpg-dev@lists.sourceforge.net
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: wfrpg.py
+# Author: Prof. Ebral, TaS (Traipse)
+# Maintainer:
+# Version:
+#   $Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $
+#
+# Description: Warhammer Fantasy Roleplay Dice Roller die roller
+# Comissioned by Puu-san
+#
+
+__version__ = "$Id: wfrpg.py,v 1.00 Jan/13/2010 prof.ebral Exp $"
+
+from std import std
+import random
+from orpg.dieroller.base import *
+
+class wfrpg(std):
+    name = "wfrpg"
+
+    def __init__(self, source=[]):
+        std.__init__(self, source)
+
+    def non_stdDie(self, s):
+        self.war_die = {'rec': self.reckless, 
+                        'con': self.conservative, 
+                        'chr': self.characteristic, 
+                        'cha': self.challenge, 
+                        'for': self.fortune, 
+                        'mis': self.misfortune, 
+                        'exp': self.expertise}
+        for key in self.war_die.keys():
+            dice = s.lower().split(key)
+            if len(dice) > 1: 
+                return self.war_die[key](int(dice[0]))
+
+    def roll(self, dice, facets):
+        for x in range(0,dice):
+            self.rolls.append(int(random.uniform(1, facets+1)))
+
+    def reckless(self, dice):
+        self.rolls = []
+        reck = {1: 'Bane', 2: 'Double Boon', 3: 'Boon & Success', 
+                4: 'Double Success', 5: 'Success & Exertion', 6: 'Blank', 
+                7: 'Bane', 8: 'Double Success', 9: 'Success & Exertion', 
+                10: 'Blank'}
+        self.roll(dice, 10)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Reckless] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def conservative(self, dice):
+        self.rolls = []
+        reck = {1: 'Boon', 2: 'Success', 3: 'Success & Boon', 
+                4: 'Success & Delay', 5: 'Blank', 6: 'Boon', 
+                7: 'Success', 8: 'Success', 9: 'Success & Delay', 
+                10: 'Success'}
+        self.roll(dice, 10)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Conservative] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def challenge(self, dice):
+        self.rolls = []
+        reck = {1: 'Challenge', 2: 'Double Challenge', 3: 'Bane', 
+                4: 'Double Bane', 5: 'Chaos Star', 6: 'Blank', 
+                7: 'Challenge', 8: 'Double Challenge'}
+        self.roll(dice, 8)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Challenge] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def characteristic(self, dice):
+        self.rolls = []
+        reck = {1: 'Boon', 2: 'Success', 3: 'Blank', 
+                4: 'Boon', 5: 'Success', 6: 'Success', 
+                7: 'Blank', 8: 'Success'}
+        self.roll(dice, 8)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Characterisitics] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def fortune(self, dice):
+        self.rolls = []
+        reck = {1: 'Success', 2: 'Blank', 3: 'Boon', 
+                4: 'Blank', 5: 'Success', 6: 'Blank'}
+        self.roll(dice, 6)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Fortune] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def misfortune(self, dice):
+        self.rolls = []
+        reck = {1: 'Challenge', 2: 'Blank', 3: 'Bane', 
+                4: 'Blank', 5: 'Challenge', 6: 'Blank'}
+        self.roll(dice, 6)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Misfortune] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+    def expertise(self, dice):
+        self.rolls = []
+        reck = {1: 'Boon', 2: 'Success', 3: 'Righteous Success', 
+                4: 'Comet', 5: 'Blank', 6: 'Boon'}
+        self.roll(dice, 6)
+        for roll in self.rolls:
+            self.data.append(reck[roll])
+        myStr = '[' + str(dice) + ' Expertise] = ('
+        for data in self.data:
+            myStr += data + ', '
+        myStr = myStr[:len(myStr)-2] + ')'
+        return myStr
+
+
+die_rollers.register(wfrpg)
+
--- a/orpg/dieroller/rollers/wod.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/dieroller/rollers/wod.py	Fri Jan 15 23:01:42 2010 -0600
@@ -65,12 +65,9 @@
                 if s1 >0:
                     s1 -= 1
                     s -= 1
-                else:
-                    botch = 1
-            elif r == 1:
-                s -= 1
-            if botch == 1 and s < 0:
-                s = 0
+                else: botch = 1
+            elif r == 1: s -= 1
+            if botch == 1 and s < 0: s = 0
         return s
 
     def __str__(self):
@@ -79,14 +76,18 @@
             for a in self.data[1:]:
                 myStr += ","
                 myStr += str(a)
-            if self.sum() < 0:
-                myStr += "] vs " +str(self.target)+" result of a botch"
-            elif self.sum() == 0:
-                myStr += "] vs " +str(self.target)+" result of a failure"
-            else:
-                myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
-
-
+            if self.sum() < 0: myStr += "] vs " +str(self.target)+" result of a botch"
+            elif self.sum() == 0: myStr += "] vs " +str(self.target)+" result of a failure"
+            else: myStr += "] vs " +str(self.target)+" result of (" + str(self.sum()) + ")"
         return myStr
 
-die_rollers.register(wod)
\ No newline at end of file
+    def non_stdDie(self, s):
+        num_sides = s.split('v')
+        if len(num_sides) > 1: 
+            num_sides; num = num_sides[0]; sides = num_sides[1]
+            sides = '10'; target = num_sides[1]
+            ret = ['(', num.strip(), "**die_rollers['wod'](",
+                    sides.strip(), ')).vs(', target, ')']
+            s = ''.join(ret); return str(eval(s))
+
+die_rollers.register(wod)
--- a/orpg/dieroller/utils.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/dieroller/utils.py	Fri Jan 15 23:01:42 2010 -0600
@@ -55,48 +55,43 @@
     def listRollers(self):
         return die_rollers.keys()
 
-    def stdDieToDClass(self,match):
+    def stdDieToDClass(self, match):
         s = match.group(0)
+        self.mod = str(match.string[len(s):])
         num_sides = s.split('d')
-        if len(num_sides) > 1: num_sides; num = num_sides[0]; sides = num_sides[1]
-        else: return self.non_stdDieToDClass(s) # Use a non standard converter.
-
-        if sides.strip().upper() == 'F': sides = "'f'"
-        try:
-            if int(num) > 100 or int(sides) > 10000: return None
-        except: pass
-        ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
-                sides.strip(), '))']
-        return ''.join(ret)
-
-    def non_stdDieToDClass(self, s):
-        num_sides = s.split('v')
         if len(num_sides) > 1: 
             num_sides; num = num_sides[0]; sides = num_sides[1]
-            if self.getRoller() == 'mythos': sides = '12'; target = num_sides[1]
-            elif self.getRoller() == 'wod': sides = '10'; target = num_sides[1]
+            if sides.strip().upper() == 'F': sides = "'f'"
+            try:
+                if int(num) > 100 or int(sides) > 10000: return None
+            except: pass
             ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
-                    sides.strip(), ')).vs(', target, ')']
-            return ''.join(ret)
-
-        num_sides = s.split('k')
-        if len(num_sides) > 1: 
-            num_sides; num = num_sides[0]; sides = '10'; target = num_sides[1]
-            ret = ['(', num.strip(), "**die_rollers['", self.getRoller(), "'](",
-                    sides.strip(), ')).takeHighest(', target, ').open(10)']
-            return ''.join(ret)
+                    sides.strip(), '))'+self.mod]
+            s =  ''.join(ret); s = str(eval(s)); return s ## Moved eval here for portability.
+        ## Portable Non Standard Die Characters #Prof-Ebral
+        else: s = die_rollers._rollers[self.getRoller()]().non_stdDie(s); self.mod = ''; return s
 
     #  Use this to convert ndm-style (3d6) dice to d_base format
     def convertTheDieString(self,s):
         reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[\dFf]+")
         (result, num_matches) = reg.subn(self.stdDieToDClass, s)
         if num_matches == 0 or result is None:
-            try:
-                s2 = self.roller_class + "(0)." + s
+            reg = re.compile("(?:\d+|\([0-9\*/\-\+]+\))\s*[a-zA-Z]+\s*[a-zA-Z]+") ## Prof Ebral
+            (result, num_matches) = reg.subn(self.stdDieToDClass, s) ## Prof Ebral
+            """try: ## Kinda pointless when you can create new Regular Expressions
+                s2 = self.roller_class + "(0)." + s ## Broken method
                 test = eval(s2)
                 return s2
+            except Exception, e: print e; pass"""
+            try: return self.do_math(s)
             except: pass
         return result
 
+    def do_math(self, s):
+        self.mod = ''
+        return str(eval(s))
+
     def proccessRoll(self, s):
-        return str(eval(self.convertTheDieString(s)))
+        v = str(self.convertTheDieString(s))
+        return v[:len(v)-len(self.mod)]
+
--- a/orpg/gametree/gametree.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/gametree/gametree.py	Fri Jan 15 23:01:42 2010 -0600
@@ -25,6 +25,15 @@
 #
 # Description: The file contains code fore the game tree shell
 #
+# 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
 
@@ -78,29 +87,32 @@
 TOP_SAVE_TREE_AS = wx.NewId()
 TOP_TREE_PROP = wx.NewId()
 TOP_FEATURES = wx.NewId()
+EZ_REF = wx.NewId()
 
 class game_tree(wx.TreeCtrl):
     
     def __init__(self, parent, id):
-        wx.TreeCtrl.__init__(self,parent,id,  wx.DefaultPosition, 
+        wx.TreeCtrl.__init__(self,parent,id, wx.DefaultPosition, 
                 wx.DefaultSize,style=wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS)
         self.chat = component.get('chat')
         self.session = component.get('session')
         self.mainframe = component.get('frame')
+        self.ez_ref = True if id == EZ_REF else False
         self.build_img_list()
-        self.build_std_menu()
+        if not self.ez_ref: self.build_std_menu()
         self.nodehandlers = {}
         self.nodes = {}
         self.init_nodehandlers()
-        self.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick)
-        self.Bind(wx.EVT_RIGHT_DOWN, self.on_rclick)
-        self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_drag, id=id)
-        self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
-        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
-        self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.on_label_change, id=self.GetId())
-        self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.on_label_begin, id=self.GetId())
-        self.Bind(wx.EVT_CHAR, self.on_char)
-        self.Bind(wx.EVT_KEY_UP, self.on_key_up)
+        if not self.ez_ref:
+            self.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick)
+            self.Bind(wx.EVT_RIGHT_DOWN, self.on_rclick)
+            self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_drag, id=id)
+            self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
+            self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
+            self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.on_label_change, id=self.GetId())
+            self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.on_label_begin, id=self.GetId())
+            self.Bind(wx.EVT_CHAR, self.on_char)
+            self.Bind(wx.EVT_KEY_UP, self.on_key_up)
         self.id = 1
         self.dragging = False
         self.last_save_dir = dir_struct["user"]
@@ -108,7 +120,13 @@
 
         #Create tree from default if it does not exist
         validate.config_file("tree.xml","default_tree.xml")
-        component.add("tree", self)
+
+        ## The EZ_Tree Reference creates a duplicate component called tree_back. This is because the
+        ## tree wont parse fully without adding the component, and when a dupplicate component is created
+        ## the older one is deleted. If there are an C++ errors the tree_back can be used as a failsafe
+
+        if not self.ez_ref: component.add("tree", self); component.add('tree_fs', self) ## Fail Safe
+        component.add('tree', self)
 
         #build tree
         self.root = self.AddRoot("Game Tree", self.icons['gear'])
@@ -206,7 +224,6 @@
             validate.config_file("tree.xml","default_tree.xml")
             self.load_tree(error=1)
             return
-
     
     def load_tree(self, filename=dir_struct["user"]+'tree.xml', error=0):
         settings.change("gametree", filename)
@@ -320,8 +337,8 @@
         self.Bind(wx.EVT_MENU, self.on_export_html, id=STD_MENU_HTML)
         self.top_menu = wx.Menu()
         self.top_menu.SetTitle("game tree")
-        self.top_menu.Append(TOP_IFILE,"&Insert File")
-        self.top_menu.Append(TOP_INSERT_URL,"Insert &URL")
+        self.top_menu.Append(TOP_IFILE,"&Insert Node File")
+        self.top_menu.Append(TOP_INSERT_URL,"Insert Node &URL")
         self.top_menu.Append(TOP_FEATURES, "Insert &Features Node")
         self.top_menu.Append(TOP_NEW_TREE, "&Load New Tree")
         self.top_menu.Append(TOP_SAVE_TREE,"&Save Tree")
@@ -662,6 +679,7 @@
         if parent_node == self.root:
             self.tree_map[xml_element.get('name')] = {}
             self.tree_map[xml_element.get('name')]['node'] = xml_element
+            xml_element.set('map', '')
         if parent_node != self.root:
             ## Loading XML seems to lag on Grids and Images need a cache for load speed ##
             family_tree = self.get_tree_map(parent_node)
--- a/orpg/gametree/nodehandlers/containers.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/gametree/nodehandlers/containers.py	Fri Jan 15 23:01:42 2010 -0600
@@ -105,7 +105,7 @@
     def load_children(self):
         self.atts = None
         for child_xml in self.xml:
-            if child_xml.get == "group_atts": #having the group attributes as a child is bad!
+            if child_xml.tag == "group_atts": #having the group attributes as a child is bad!
                 self.xml.remove(child_xml)
             elif child_xml: self.tree.load_xml(child_xml, self.mytree_node)
         if not self.xml.get('cols'): self.xml.set('cols', '1')
@@ -200,11 +200,11 @@
     def __init__(self, xml, tree_node):
         container_handler.__init__(self, xml, tree_node)
 
-    def get_design_panel(self,parent):
-        return tabbed_edit_panel(parent, self)
+    def get_design_panel(self, parent):
+        return tabbed_panel(parent, self, 1)
 
-    def get_use_panel(self,parent):
-        return tabbed_panel(parent, self, 1)
+    def get_use_panel(self, parent):
+        return tabbed_panel(parent, self, 0)
 
 
 class tabbed_panel(orpgTabberWnd):
@@ -212,11 +212,13 @@
         orpgTabberWnd.__init__(self, parent, style=FNB.FNB_NO_X_BUTTON)
         self.handler = handler
         self.parent = parent
+        if mode == 1: self.AddPage(tabbed_edit_panel(parent, handler), 'Tabber', False)
         handler.tree.traverse(handler.mytree_node, self.pick_panel, mode, False)
         parent.SetSize(self.GetBestSize())
 
     def pick_panel(self, treenode, mode):
         node = self.handler.tree.GetPyData(treenode)
+
         if mode == 1: panel = node.get_design_panel(self)
         else: panel = node.get_use_panel(self)
         name = node.xml.get("name")
@@ -228,9 +230,9 @@
                 component.get('frame').TraipseSuiteWarn('item')
         if panel: self.AddPage(panel, name, False)
 
-class tabbed_edit_panel(orpgTabberWnd):
+class tabbed_edit_panel(wx.Panel):
     def __init__(self, parent, handler):
-        orpgTabberWnd.__init__(self, parent, style=FNB.FNB_NO_X_BUTTON)
+        wx.Panel.__init__(self, parent, -1, style=FNB.FNB_NO_X_BUTTON)
         self.handler = handler
         self.parent = parent
         main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Tabber"), wx.VERTICAL)
@@ -240,8 +242,10 @@
         self.SetSizer(main_sizer)
         self.SetAutoLayout(True)
         self.Fit()
+        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 != "":
@@ -262,7 +266,7 @@
     def load_children(self):
         self.atts = None
         for child_xml in self.xml:
-            if child_xml.tag == "splitter_atts": self.xml.remove(child_xml) #Same here!
+            if child_xml.tag == "splitter_atts": print 'splitter_atts exist!'; self.xml.remove(child_xml) #Same here!
             elif child_xml: self.tree.load_xml(child_xml,self.mytree_node)
         if not self.xml.get('horizontal'): self.xml.set('horizontal', '0')
 
@@ -270,7 +274,7 @@
         return self.build_splitter_wnd(parent, 1)
 
     def get_use_panel(self,parent):
-        return self.build_splitter_wnd(parent, 2)
+        return self.build_splitter_wnd(parent, 0)
 
     def on_drop(self,evt):
         drag_obj = self.tree.drag_obj
--- a/orpg/gametree/nodehandlers/core.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/gametree/nodehandlers/core.py	Fri Jan 15 23:01:42 2010 -0600
@@ -54,6 +54,7 @@
         self.xml = xml
         self.mytree_node = tree_node
         self.tree = component.get('tree')
+        #self.tree = component.get('tree_fs')
         self.frame = component.get('frame')
         self.chat = component.get('chat')
         self.drag = True
@@ -132,7 +133,7 @@
         self.myeditor.Thaw()
         return True
 
-    def on_use(self,evt):
+    def on_use(self, evt):
         try:
             self.mywindow.Show()
             self.mywindow.Raise()
@@ -423,7 +424,6 @@
 
     def on_design(self,evt):
         tlist = ['Title','URL']
-        print "design filename",self.xml.get('name')
         vlist = [self.xml.get("name"),
                  self.file_node.get("url")]
         dlg = orpgMultiTextEntry(self.tree.GetParent(),tlist,vlist,"File Loader Edit")
--- a/orpg/gametree/nodehandlers/forms.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/gametree/nodehandlers/forms.py	Fri Jan 15 23:01:42 2010 -0600
@@ -32,6 +32,7 @@
 import orpg.minidom as minidom
 from orpg.orpg_xml import xml
 from wx.lib.scrolledpanel import ScrolledPanel
+from orpg.tools.settings import settings
 
 def bool2int(b):
     #in wxPython 2.5+, evt.Checked() returns True or False instead of 1.0 or 0.
@@ -255,7 +256,6 @@
         self.Bind(wx.EVT_BUTTON, self.on_send, id=FORM_SEND_BUTTON)
 
     def on_text(self, evt):
-        debug()
         txt = self.text.GetValue()
         #txt = strip_text(txt) ##Does not seem to exist.
         self.handler.text_elem.text = txt
@@ -263,6 +263,7 @@
     def on_send(self, evt):
         txt = self.text.GetValue()
         txt = self.chat.ParseMap(txt, self.handler.xml)
+        txt = self.chat.ParseParent(txt, self.handler.xml.get('map'))
         if not self.handler.is_raw_send():
             self.chat.ParsePost(self.handler.tohtml(), True, True)
             return 1
@@ -281,11 +282,13 @@
 F_RAW_SEND = wx.NewId()
 F_HIDE_TITLE = wx.NewId()
 F_TEXT = wx.NewId()
+T_BUT_REF = wx.NewId()
 
 class textctrl_edit_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
+        self.parent = parent
         sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Text Properties"), wx.VERTICAL)
 
         self.title = wx.TextCtrl(self, P_TITLE, handler.xml.get('name'))
@@ -297,6 +300,7 @@
         self.hide_title.SetValue(handler.is_hide_title())
         self.send_button = wx.CheckBox(self, F_SEND_BUTTON, " Send Button")
         self.send_button.SetValue(handler.has_send_button())
+        button_ref = wx.Button(self, T_BUT_REF, "Reference")
 
         sizer.Add(wx.StaticText(self, P_TITLE, "Title:"), 0, wx.EXPAND)
         sizer.Add(self.title, 0, wx.EXPAND)
@@ -305,6 +309,7 @@
         sizer.Add(self.raw_send, 0, wx.EXPAND)
         sizer.Add(self.hide_title, 0, wx.EXPAND)
         sizer.Add(self.send_button, 0 , wx.EXPAND)
+        sizer.Add(button_ref, 0)
         sizer.Add(wx.Size(10,10))
         if handler.is_multi_line():
             sizer_style = wx.EXPAND
@@ -326,6 +331,79 @@
         self.Bind(wx.EVT_CHECKBOX, self.on_raw_button, id=F_RAW_SEND)
         self.Bind(wx.EVT_CHECKBOX, self.on_hide_button, id=F_HIDE_TITLE)
         self.Bind(wx.EVT_CHECKBOX, self.on_send_button, id=F_SEND_BUTTON)
+        self.Bind(wx.EVT_BUTTON, self.on_reference, id=T_BUT_REF)
+        self.parent.Bind(wx.EVT_CLOSE, self.tree_failsafe)
+
+    ## EZ_Tree Core TaS - Prof.Ebral ##
+    def on_reference(self, evt, car=None):
+        self.do_tree = wx.Frame(self, -1, 'EZ Tree')
+        self.ez_tree = orpg.gametree.gametree
+        self.temp_wnd = self.ez_tree.game_tree(self.do_tree, self.ez_tree.EZ_REF)
+        self.temp_wnd.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick)
+        component.get('tree_fs').save_tree(settings.get("gametree"))
+        self.temp_wnd.load_tree(settings.get("gametree"))
+        self.do_tree.Show()
+
+    def tree_failsafe(self, evt):
+        self.parent.Destroy()
+        component.add('tree', component.get('tree_fs')) ## Backup
+
+    def get_grid_ref(self, obj, complete):
+        self.temp_wnd.Freeze()
+        self.grid_ref = complete
+        self.mini_grid = wx.Frame(self, -1, 'EZ Tree Mini Grid')
+        self.temp_grid = obj.get_use_panel(self.mini_grid)
+        self.temp_grid.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_grid_ldclick)
+        self.mini_grid.Show()
+
+    def on_grid_ldclick(self, evt):
+        complete = self.grid_ref
+        row = str(evt.GetRow()+1)
+        col = str(evt.GetCol()+1)
+        complete = complete[:len(complete)-2] + '::'+'('+row+','+col+')'+complete[len(complete)-2:]
+        self.text.AppendText(complete); self.on_text(evt)
+        self.mini_grid.Destroy()
+
+    def on_ldclick(self, evt):
+        self.rename_flag = 0
+        pt = evt.GetPosition()
+        (item, flag) = self.temp_wnd.HitTest(pt)
+        if item.IsOk():
+            obj = self.temp_wnd.GetPyData(item)
+            self.temp_wnd.SelectItem(item)
+            start = self.handler.xml.get('map').split('::')
+            end = obj.xml.get('map').split('::')
+            if obj.xml.get('class') not in ['rpg_grid_handler', 'textctrl_handler']: do = 'None'
+            elif end[0] == '' or start[0] != end[0]: do = 'Root'
+            elif start == end: do = 'Child'
+            elif start != end: do = 'Parent'
+            if do == 'Root':
+                complete = "!@"
+                for e in end: 
+                    if e != '': complete += e +'::'
+                complete = complete + obj.xml.get('name') + '@!'
+            elif do == 'Parent':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!#"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '#!'
+            elif do == 'Child':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!!"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '!!'
+            if do != 'None': 
+                if obj.xml.get('class') == 'rpg_grid_handler': 
+                    self.get_grid_ref(obj, complete)
+                else: self.text.AppendText(complete); self.on_text(evt)
+        self.do_tree.Destroy()
+        if do == 'None':
+            wx.MessageBox('Invalid Reference', 'Error')
+    #####                        #####
 
     def on_text(self,evt):
         id = evt.GetId()
@@ -377,12 +455,21 @@
     """
     def __init__(self,xml,tree_node):
         node_handler.__init__(self,xml,tree_node)
-        self.list = self.xml.find('list')
-        self.options = self.list.findall('option')
+        self.list_reload()
+        #print xml
+        #print self.tree.GetItemParent(tree_node)
         if self.list.get("send_button") == "": self.list.set("send_button","0")
         if self.list.get("hide_title") == "": self.list.set("hide_title","0")
         if self.list.get("raw_mode") == "": self.list.set("raw_mode","0")
 
+    def list_reload(self):
+        self.list = self.xml.find('list')
+        self.options = self.list.findall('option')
+        self.captions = []
+        for opt in self.options:
+            if opt.get('caption') == None: opt.set('caption', '')
+            self.captions.append(opt.get('caption'))
+
     def get_design_panel(self,parent):
         return listbox_edit_panel(parent,self)
 
@@ -454,24 +541,39 @@
         for opt in self.options: opts.append(opt.text)
         return opts
 
-    def get_option(self,index):
+    def get_captions(self):
+        captions = []
+        for opt in self.options: captions.append(opt.get("caption"))
+        self.captions = captions
+        return captions
+
+    def get_option(self, index):
         return self.options[index].text
 
-    def add_option(self,opt):
+    def get_caption(self, index):
+        captions = self.get_captions()
+        return captions[index] or ''
+
+    def add_option(self, caption, value):
         elem = Element('option')
         elem.set("value","0")
+        elem.set('caption', caption)
         elem.set("selected","0")
-        elem.text = opt
+        elem.text = value
         self.list.append(elem)
-        self.options = self.list.findall('option')
+        self.list_reload()
 
     def remove_option(self,index):
         self.list.remove(self.options[index])
-        self.options = self.list.findall('option')
+        self.list_reload()
 
-    def edit_option(self,index,value):
+    def edit_option(self, index, value):
         self.options[index].text = value
 
+    def edit_caption(self, index, value):
+        self.options[index].set('caption', value)
+        self.captions[index] = value
+
     def has_send_button(self):
         if self.list.get("send_button") == '0': return False
         else: return True
@@ -494,12 +596,14 @@
     def on_send_to_chat(self, evt):
         txt = self.get_selected_text()
         txt = self.chat.ParseMap(txt, self.xml)
+        txt = self.chat.ParseParent(txt, self.xml.get('map'))
         if not self.is_raw_send():
             self.chat.ParsePost(self.tohtml(), True, True)
             return 1
         actionlist = self.get_selections_text()
         for line in actionlist:
             line = self.chat.ParseMap(line, self.xml)
+            line = self.chat.ParseParent(line, self.xml.get('map'))
             if(line != ""):
                 if line[0] != "/": ## it's not a slash command
                     self.chat.ParsePost(line, True, True)
@@ -518,7 +622,12 @@
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
         self.chat = handler.chat
-        opts = handler.get_options()
+        opts = []
+        values = handler.get_options()
+        captions = handler.get_captions()
+        for value in values:
+            if captions[values.index(value)] != '': opts.append(captions[values.index(value)])
+            else: opts.append(value)
         cur_opt = handler.get_selected_text()
         type = handler.get_type()
         label = handler.xml.get('name')
@@ -571,20 +680,27 @@
 
 BUT_ADD = wx.NewId()
 BUT_REM = wx.NewId()
+BUT_REF = wx.NewId()
 BUT_EDIT = wx.NewId()
 F_TYPE = wx.NewId()
 F_NO_TITLE = wx.NewId()
+LIST_CTRL = wx.NewId()
 
 class listbox_edit_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
+        self.parent = parent
         sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "List Box Properties"), wx.VERTICAL)
 
         self.text = wx.TextCtrl(self, P_TITLE, handler.xml.get('name'))
+        self.listbox = wx.ListCtrl(self, LIST_CTRL, style=wx.LC_REPORT)
+        self.listbox.InsertColumn(0, 'Caption')
+        self.listbox.InsertColumn(1, 'Value')
+        self.listbox.SetColumnWidth(0, 75)
+        self.listbox.SetColumnWidth(1, 300)
+        self.reload_options()
 
-        opts = handler.get_options()
-        self.listbox = wx.ListBox(self, F_LIST, choices=opts, style=wx.LB_HSCROLL|wx.LB_SINGLE|wx.LB_NEEDED_SB)
         opts = ['Drop Down', 'List Box', 'Radio Box', 'Check List']
         self.type_radios = wx.RadioBox(self,F_TYPE,"List Type",choices=opts)
         self.type_radios.SetSelection(handler.get_type())
@@ -636,32 +752,154 @@
         self.handler.set_type(evt.GetInt())
 
     def on_add(self,evt):
-        dlg = wx.TextEntryDialog(self, 'Enter option?','Add Option', '')
-        if dlg.ShowModal() == wx.ID_OK:
-            self.handler.add_option(dlg.GetValue())
-        dlg.Destroy()
+        self.dlg = wx.Frame(self, -1, 'Text', size=(300,150))
+        edit_panel = wx.Panel(self.dlg, -1)
+        sizer = wx.GridBagSizer(1, 2)
+        edit_panel.SetSizer(sizer)
+        caption_text = wx.StaticText(edit_panel, -1, 'Caption')
+        self.caption_entry = wx.TextCtrl(edit_panel, -1, '')
+        value_text = wx.StaticText(edit_panel, -1, 'Value') 
+        self.value_entry = wx.TextCtrl(edit_panel, -1, '')
+        button_ok = wx.Button(edit_panel, wx.ID_OK)
+        button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
+        button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
+        sizer.Add(caption_text, (0,0))
+        sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(value_text, (1,0))
+        sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+        sizer.Add(button_ok, (3,0))
+        sizer.Add(button_cancel, (3,1))
+        sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+        self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
+        self.Bind(wx.EVT_BUTTON, self.on_add_option, id=wx.ID_OK)
+        self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
+        self.dlg.Show()
+
+    def on_add_option(self, evt):
+        self.handler.add_option(self.caption_entry.GetValue(), self.value_entry.GetValue())
         self.reload_options()
+        self.dlg.Destroy()
+        component.add('tree', component.get('tree_fs')) ## Backup
+        return
+
+    ## EZ_Tree Core TaS - Prof.Ebral ##
+    def on_reference(self, evt, car=None):
+        self.do_tree = wx.Frame(self, -1, 'EZ Tree')
+        self.ez_tree = orpg.gametree.gametree
+        self.temp_wnd = self.ez_tree.game_tree(self.do_tree, self.ez_tree.EZ_REF)
+        self.temp_wnd.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick)
+        component.get('tree_fs').save_tree(settings.get("gametree"))
+        self.temp_wnd.load_tree(settings.get("gametree"))
+        self.do_tree.Show()
+
+    def get_grid_ref(self, obj, complete):
+        self.temp_wnd.Freeze()
+        self.grid_ref = complete
+        self.mini_grid = wx.Frame(self, -1, 'EZ Tree Grid')
+        self.temp_grid = obj.get_use_panel(self.mini_grid)
+        self.temp_grid.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_grid_ldclick)
+        self.mini_grid.Show()
+
+    def on_grid_ldclick(self, evt):
+        complete = self.grid_ref
+        row = str(evt.GetRow()+1)
+        col = str(evt.GetCol()+1)
+        complete = complete[:len(complete)-2] + '::'+'('+row+','+col+')'+complete[len(complete)-2:]
+        self.value_entry.AppendText(complete)
+        self.mini_grid.Destroy()
+
+    def on_ldclick(self, evt):
+        self.rename_flag = 0
+        pt = evt.GetPosition()
+        (item, flag) = self.temp_wnd.HitTest(pt)
+        if item.IsOk():
+            obj = self.temp_wnd.GetPyData(item)
+            self.temp_wnd.SelectItem(item)
+            start = self.handler.xml.get('map').split('::')
+            end = obj.xml.get('map').split('::')
+            if obj.xml.get('class') not in ['rpg_grid_handler', 'textctrl_handler']: do = 'None'
+            elif end[0] == '' or start[0] != end[0]: do = 'Root'
+            elif start == end: do = 'Child'
+            elif start != end: do = 'Parent'
+            if do == 'Root':
+                complete = "!@"
+                for e in end: 
+                    if e != '': complete += e +'::'
+                complete = complete + obj.xml.get('name') + '@!'
+            elif do == 'Parent':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!#"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '#!'
+            elif do == 'Child':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!!"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '!!'
+            if do != 'None': 
+                if obj.xml.get('class') == 'rpg_grid_handler': 
+                    self.get_grid_ref(obj, complete)
+                else: self.value_entry.AppendText(complete); self.reload_options()
+        self.do_tree.Destroy()
+        if do == 'None':
+            wx.MessageBox('Invalid Reference', 'Error')
+    #####                        #####
+
+    def on_edit_ok(self, evt):
+        self.handler.edit_caption(self.index, self.caption_entry.GetValue())
+        self.handler.edit_option(self.index, self.value_entry.GetValue())
+        self.reload_options()
+        self.dlg.Destroy()
+        component.add('tree', component.get('tree_fs')) ## Backup
+        return
+
+    def on_edit_cancel(self, evt):
+        self.dlg.Destroy()
+        component.add('tree', component.get('tree_fs')) ## Backup
+        return
 
     def on_remove(self,evt):
-        index = self.listbox.GetSelection()
+        index = self.listbox.GetFocusedItem()
         if index >= 0:
             self.handler.remove_option(index)
             self.reload_options()
 
     def on_edit(self,evt):
-        index = self.listbox.GetSelection()
-        if index >= 0:
-            txt = self.handler.get_option(index)
-            dlg = wx.TextEntryDialog(self, 'Enter option?','Edit Option', txt)
-            if dlg.ShowModal() == wx.ID_OK:
-                self.handler.edit_option(index,dlg.GetValue())
-            dlg.Destroy()
-            self.reload_options()
+        self.index = self.listbox.GetFocusedItem()
+        if self.index >= 0:
+            self.dlg = wx.Frame(self, -1, 'Text', size=(300,150))
+            edit_panel = wx.Panel(self.dlg, -1)
+            sizer = wx.GridBagSizer(1, 2)
+            edit_panel.SetSizer(sizer)
+            caption_text = wx.StaticText(edit_panel, -1, 'Caption')
+            self.caption_entry = wx.TextCtrl(edit_panel, -1, self.handler.get_caption(self.index))
+            value_text = wx.StaticText(edit_panel, -1, 'Value') 
+            self.value_entry = wx.TextCtrl(edit_panel, -1, self.handler.get_option(self.index))
+            button_ok = wx.Button(edit_panel, wx.ID_OK)
+            button_cancel = wx.Button(edit_panel, wx.ID_CANCEL)
+            button_ref = wx.Button(edit_panel, BUT_REF, "Reference")
+            sizer.Add(caption_text, (0,0))
+            sizer.Add(self.caption_entry, (0,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(value_text, (1,0))
+            sizer.Add(self.value_entry, (1,1), span=(1,3), flag=wx.EXPAND)
+            sizer.Add(button_ok, (3,0))
+            sizer.Add(button_cancel, (3,1))
+            sizer.Add(button_ref, (3,2), flag=wx.EXPAND)
+            self.Bind(wx.EVT_BUTTON, self.on_reference, id=BUT_REF)
+            self.Bind(wx.EVT_BUTTON, self.on_edit_ok, id=wx.ID_OK)
+            self.Bind(wx.EVT_BUTTON, self.on_edit_cancel, id=wx.ID_CANCEL)
+            self.dlg.Show()
 
     def reload_options(self):
-        self.listbox.Clear()
-        for opt in self.handler.get_options():
-            self.listbox.Append(opt)
+        self.listbox.DeleteAllItems()
+        values = self.handler.get_options()
+        captions = self.handler.get_captions()
+        for index in range(len(values)):
+            self.listbox.Append((captions[index], values[index]))
 
     def on_text(self,evt):
         id = evt.GetId()
--- a/orpg/gametree/nodehandlers/rpg_grid.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/gametree/nodehandlers/rpg_grid.py	Fri Jan 15 23:01:42 2010 -0600
@@ -366,7 +366,7 @@
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
-        self.grid = rpg_grid(self,handler)
+        self.grid = rpg_grid(self, handler)
         label = handler.xml.get('name')
         self.main_sizer = wx.BoxSizer(wx.VERTICAL)
         self.main_sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
@@ -381,11 +381,13 @@
 G_ADD_COL = wx.NewId()
 G_DEL_ROW = wx.NewId()
 G_DEL_COL = wx.NewId()
+G_BUT_REF = wx.NewId()
 
 class rpg_grid_edit_panel(wx.Panel):
     def __init__(self, parent, handler):
         wx.Panel.__init__(self, parent, -1)
         self.handler = handler
+        self.parent = parent
         self.grid = rpg_grid(self,handler)
         self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Grid"), wx.VERTICAL)
 
@@ -407,6 +409,8 @@
         sizer.Add(wx.Button(self, G_ADD_COL, "Add Column"), 1, wx.EXPAND)
         sizer.Add(wx.Size(10,10))
         sizer.Add(wx.Button(self, G_DEL_COL, "Remove Column"), 1, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        sizer.Add(wx.Button(self, G_BUT_REF, "Reference"), 1)
 
         self.main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
         self.main_sizer.Add(self.title, 0, wx.EXPAND)
@@ -426,6 +430,88 @@
         self.Bind(wx.EVT_BUTTON, self.grid.del_col, id=G_DEL_COL)
         self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=GRID_BOR)
         self.Bind(wx.EVT_CHECKBOX, self.on_auto_size, id=G_AUTO_SIZE)
+        self.Bind(wx.EVT_BUTTON, self.on_reference, id=G_BUT_REF)
+        self.parent.Bind(wx.EVT_CLOSE, self.tree_failsafe)
+
+    ## EZ_Tree Core TaS - Prof.Ebral ##
+    def on_reference(self, evt, car=None):
+        self.do_tree = wx.Frame(self, -1, 'EZ Tree')
+        self.ez_tree = orpg.gametree.gametree
+        self.temp_wnd = self.ez_tree.game_tree(self.do_tree, self.ez_tree.EZ_REF)
+        self.temp_wnd.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick) ## Remove for Alpha ##
+        component.get('tree_fs').save_tree(settings.get("gametree"))
+        self.temp_wnd.load_tree(settings.get("gametree"))
+        self.do_tree.Show()
+
+    def tree_failsafe(self, evt):
+        self.parent.Destroy()
+        component.add('tree', component.get('tree_fs')) ## Backup
+
+    def get_grid_ref(self, obj, complete):
+        self.temp_wnd.Freeze()
+        self.grid_ref = complete
+        self.mini_grid = wx.Frame(self, -1, 'EZ Tree Mini Grid')
+        self.temp_grid = obj.get_use_panel(self.mini_grid)
+        self.temp_grid.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_grid_ldclick)
+        self.mini_grid.Show()
+
+    def on_grid_ldclick(self, evt):
+        complete = self.grid_ref
+        row = str(evt.GetRow()+1)
+        col = str(evt.GetCol()+1)
+        complete = complete[:len(complete)-2] + '::'+'('+row+','+col+')'+complete[len(complete)-2:]
+        col = self.grid.GetGridCursorCol()
+        row = self.grid.GetGridCursorRow()
+        self.grid.SetCellValue(row, col, complete)
+        cells = self.grid.rows[row].findall('cell')
+        cells[col].text = complete
+        self.mini_grid.Destroy()
+
+    def on_ldclick(self, evt):
+        self.rename_flag = 0
+        pt = evt.GetPosition()
+        (item, flag) = self.temp_wnd.HitTest(pt)
+        if item.IsOk():
+            obj = self.temp_wnd.GetPyData(item)
+            self.temp_wnd.SelectItem(item)
+            start = self.handler.xml.get('map').split('::')
+            end = obj.xml.get('map').split('::')
+            if obj.xml.get('class') not in ['rpg_grid_handler', 'textctrl_handler']: do = 'None'
+            elif end[0] == '' or start[0] != end[0]: do = 'Root'
+            elif start == end: do = 'Child'
+            elif start != end: do = 'Parent'
+            if do == 'Root':
+                complete = "!@"
+                for e in end: 
+                    if e != '': complete += e +'::'
+                complete = complete + obj.xml.get('name') + '@!'
+            elif do == 'Parent':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!#"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '#!'
+            elif do == 'Child':
+                while start[0] == end[0]:
+                    del end[0], start[0]
+                    if len(start) == 0 or len(end) == 0: break
+                complete = "!!"
+                for e in end: complete += e +'::'
+                complete = complete + obj.xml.get('name') + '!!'
+            if do != 'None':
+                if obj.xml.get('class') == 'rpg_grid_handler': 
+                    self.get_grid_ref(obj, complete)
+                else:
+                    col = self.grid.GetGridCursorCol()
+                    row = self.grid.GetGridCursorRow()
+                    self.grid.SetCellValue(row, col, complete)
+                    cells = self.grid.rows[row].findall('cell')
+                    cells[col].text = complete
+        self.do_tree.Destroy()
+        if do == 'None':
+            wx.MessageBox('Invalid Reference', 'Error')
+    #####                        #####
 
     def on_auto_size(self,evt):
         self.handler.set_autosize(bool2int(evt.Checked()))
--- a/orpg/main.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/main.py	Fri Jan 15 23:01:42 2010 -0600
@@ -631,6 +631,9 @@
         #self.manifest = manifest.ManifestChanges()
         self.updateMana = upmana.updatemana.updaterFrame(self, 
             "OpenRPG Update Manager 1.0", component, manifest, True)
+        print component.get('upmana-win')
+        component.add('upmana-win', self.updateMana)
+        print component.get('upmana-win')
         logger.debug("Menu Created")
         h = int(xml_dom.get("height"))
         w = int(xml_dom.get("width"))
@@ -943,7 +946,7 @@
 
         for child in etreeEl.getchildren():
             if child.tag == 'tree':
-                dlg = wx.MessageDialog(None, display_name + ' is trying to send you a tree node. Accept?', 'Question', 
+                dlg = wx.MessageDialog(None, component.strip_html(display_name) + ' is trying to send you a tree node. Accept?', 'Question', 
                     wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                 if dlg.ShowModal() == wx.ID_YES:
                   dlg.Destroy()
--- a/orpg/mapper/images.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/mapper/images.py	Fri Jan 15 23:01:42 2010 -0600
@@ -106,7 +106,7 @@
             self.__fetching = {}
             urllib.urlcleanup()
 
-#Private Methods
+    #Private Methods
     def __loadThread(self, path, image_type, imageId):
         uriPath = urllib.unquote(path)
         try:
@@ -121,11 +121,13 @@
             else:
                 logger.general("Image refused to load or URI did not "
                                "reference a valid image: " + path, True)
+                self.__queue.put(('failed', image_type, imageId))
                 del self.__fetching[path]
         except IOError:
             del self.__fetching[path]
             logger.general("Unable to resolve/open the specified URI; "
                            "image was NOT laoded: " + path, True)
+            self.__queue.put((dir_struct["icon"] + "failed.png", image_type, imageId))
 
     def __loadCacheThread(self, path, image_type, imageId):
         try:
--- a/orpg/mapper/map.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/mapper/map.py	Fri Jan 15 23:01:42 2010 -0600
@@ -156,7 +156,8 @@
             else: pass
         if not ImageHandler.Queue.empty():
             (path, image_type, imageId) = ImageHandler.Queue.get()
-            img = wx.ImageFromMime(path[1], path[2])
+            if path == 'failed': 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
                 if image_type == "miniature":
@@ -472,8 +473,8 @@
 
     def on_left_up(self, evt):
         if evt.ShiftDown(): self.on_tape_up(evt)
-        elif component.get("tree").dragging:
-            tree = component.get("tree")
+        elif component.get('tree_fs').dragging:
+            tree = component.get('tree_fs')
             if tree.drag_obj.map_aware():
                 tree.drag_obj.on_send_to_map(evt)
                 tree.dragging = False
@@ -482,7 +483,7 @@
 
     def on_motion(self, evt):
         if evt.ShiftDown(): self.on_tape_motion(evt)
-        elif evt.LeftIsDown() and component.get("tree").dragging: pass
+        elif evt.LeftIsDown() and component.get('tree_fs').dragging: pass
         else: self.frame.on_motion(evt)
 
     def on_zoom_out(self, evt):
--- a/orpg/mapper/miniatures_handler.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/mapper/miniatures_handler.py	Fri Jan 15 23:01:42 2010 -0600
@@ -357,8 +357,8 @@
             node.set('class', 'map_miniature_handler')
             name = self.sel_rmin.label if self.sel_rmin.label else 'Unnamed Miniature'
             node.set('name', name)
-            node.append(mini)
-            gametree = component.get('tree')
+            node.append(fromstring(mini))
+            gametree = component.get('tree_fs')
             gametree.insert_xml(tostring(node))
             ### ElementTree is a nice decision from Core, kudos!! ###
         elif id == MIN_SHOW_HIDE:
--- a/orpg/networking/mplay_server.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/networking/mplay_server.py	Fri Jan 15 23:01:42 2010 -0600
@@ -2145,6 +2145,7 @@
         except: pass
 
     def send(self,msg,player,group):
+        debug(msg)
         self.players[player].send(msg,player,group)
 
     def send_to_all(self,from_id,data):
@@ -2159,8 +2160,9 @@
             self.log_msg("Exception: send_to_all(): " + str(e))
 
     def send_to_group(self, from_id, group_id, data):
-        #data = ("<msg to='all' from='0' group_id='"+str(group_id)+"'><font color='#FF0000'>" + data + "</font>")
+        #data = ("<msg to='all' from='0' group_id='"+str(group_id)+"' /><font color='#FF0000'>" + data + "</font>")
         data = ServerPlugins.postParseIncoming(data) #Function breaks here.
+        debug(data)
         try:
             self.p_lock.acquire()
             keys = self.groups[group_id].get_player_ids()
@@ -2520,7 +2522,7 @@
             keys.sort(id_compare)
             for k in keys:
                 groupstring = "<tr><td bgcolor='" + COLOR2 + "' colspan='2'>"
-                groutstring += "<b>Group " + str(k)  + ": " +  self.groups[k].name  + "</b>"
+                groupstring += "<b>Group " + str(k)  + ": " +  self.groups[k].name  + "</b>"
                 groupstring += "</td><td bgcolor=" + COLOR2 + " > <i>Password: " + self.groups[k].pwd + "</td>"
                 groupstring += "<td bgcolor=" + COLOR2 + " > Boot: " + self.groups[k].boot_pwd + "</i></td></tr>"
                 pl += groupstring
--- a/orpg/orpgCore.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/orpgCore.py	Fri Jan 15 23:01:42 2010 -0600
@@ -71,6 +71,16 @@
         if self.__components.has_key(key): del self.__components[key]
         else: return
 
+    def strip_html(self, string):
+        ret_string = ""; x = 0; in_tag = 0
+        for x in range(len(string)) :
+            if string[x] == "<" or string[x] == ">" or in_tag == 1 :
+                if string[x] == "<": in_tag = 1
+                elif string[x] == ">": in_tag = 0
+                else: pass
+            else: ret_string = ret_string + string[x]
+        return ret_string
+
     ###Grumpy to Ornery###
     def add_component(self, key, com):
         return self.add(key, com)
--- a/orpg/orpg_version.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/orpg_version.py	Fri Jan 15 23:01:42 2010 -0600
@@ -4,7 +4,7 @@
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
 DISTRO = "Traipse Beta"
 DIS_VER = "Ornery Orc"
-BUILD = "091210-01"
+BUILD = "100115-00"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- a/orpg/templates/default_Lobby_map.xml	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/templates/default_Lobby_map.xml	Fri Jan 15 23:01:42 2010 -0600
@@ -1,7 +1,7 @@
 <nodehandler class="min_map" icon="compass" module="core" name="miniature Map">
 <map version='1.0' sizex='650' sizey='384' action='new'>
 <grid size='50'  mode='0' line='0' snap='1' color='#000000'/>
-<bg path='http://www.knowledgearcana.com/arcane-art/Traipse_Skeleton.png' type='2'/>
+<bg path='http://www.knowledgearcana.com/arcane-art/ornery-orc-small.png' type='2'/>
 <miniatures serial='2'/>
 </map>
 </nodehandler>
--- a/orpg/templates/feature.xml	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/templates/feature.xml	Fri Jan 15 23:01:42 2010 -0600
@@ -1,53 +1,61 @@
-<nodehandler class="tabber_handler" icon="help" module="containers" name="Traipse OpenRPG" version="1.0">
+<nodehandler class="tabber_handler" icon="help" map="" module="containers" name="Traipse OpenRPG" version="1.0">
   <nodehandler class="tabber_handler" frame="499,524,156,129" icon="labtop" map="Traipse OpenRPG" module="containers" name="User Manual" version="1.0"><nodehandler class="tabber_handler" frame="410,490,334,45" icon="tabber" map="Traipse OpenRPG::User Manual" module="containers" name="Reference Examples" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,484,144" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Quick Help" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">Quick Help:
-
-The referencing system is an update to the Core of how the Game Tree works.  In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further
-
-A.
-Think of the Game Tree has a folder on your hard drive. Each :: inside the reference syntax works just like a system separator (/ or \)
-
-B.
-Root References start at the tree itself. If the node being referenced changes location the reference will be invalid.
-
-C.
-Child References work at the location of the node containing the reference. 
-
-Example: 
-Game Tree
-- Group
--- Text Node
---- Group_2
----- Text Node_2
-
-In the above Tree example you can reference Text Node_2 with a root reference
-
-!@Group::Group_2::Text Node_2@!
-
-or you can use a Child Reference from within Text Node
-
-!!Group_2::Text Node_2!!
-
-D.
-Parent References work with the Tree Map. Currently Parent References work only when called from a node that has been referenced with a Child Reference. 
-
-This is a bug in the system and is created because the Game Tree currently does not contain a Tree Map. So when you Reference a node using a Root Reference it does not pass a Tree Map for the Parent Reference to look at.
-
-Using the above example, you could reference Text Node from Text Node_2 with the syntax: !#Group::Text Node#! .. but only if you referenced Text Node with the Child Reference.
-
-(That last one is hard to understand, I know. )
-
-The reference system is still a bit primitive in it's implementation.  As I was saying it is an advancement to the Core technology of Traipse OpenRPG.
-
-While it is confusing at first, the model is far superior to other tree referencing systems.  Pre 1.8.0, no node could reference a Grid. The referencing system required the reference to be exact and started at the root. Also, the new model is designed to enable freedom of creation and greater control over the Game Tree.
-
-With the Traipse Game Tree GMs are enabled to reference any data from the Game Tree, no matter where it stands. Players can create fewer nodes and use more of the data with fewer nodes.
-
-Developer Note:
-The syntax is the hardest part to understand and I expect to change that in the future. The Core of a more expansive Game Tree model is designed. In Traipse you do not need to give access permissions to a node in order to reference it's entirety, which is what I see with Index and Namespace from OpenRPG Core.
-
-In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location.
-
+  <text multiline="1" raw_mode="1" send_button="1">Quick Help:
+
+The referencing system is an update to the Core of how the Game Tree works.  In it's current state I understand the syntax is difficult to pick up. Here are some tips to help you grasp the syntax further
+
+A.
+Think of the Game Tree has a folder on your hard drive. Each :: inside the reference syntax works just like a system separator (/ or \)
+
+B.
+Root References start at the tree itself. If the node being referenced changes location the reference will be invalid.
+
+C.
+Child References work at the location of the node containing the reference. 
+
+Example: 
+Game Tree
+- Group
+-- Text Node
+--- Group_2
+---- Text Node_2
+--- Group_3
+---- Text Node_3
+
+In the above Tree example you can reference Text Node_2 with a root reference
+
+!@Group::Group_2::Text Node_2@!
+
+or you can use a Child Reference from within Text Node
+
+!!Group_2::Text Node_2!!
+
+D.
+Parent References work with the Tree Map. Unlike Child references that look only at the current nodes location, Parent References are allowed to travel backwards in the gametree. 
+
+Using the above example, you could reference Text Node from Text Node_2 with the syntax: !#Group::Text Node#!
+
+Parent References have a special power in that they need only a certain amount of data for the software to understand them. In the above example you could reference Text Node_3 from Text Node_2 with only this syntax !#Group_3::Text Node_3#!
+
+The reference system is still a bit primitive in it's implementation.  As I was saying it is an advancement to the Core technology of Traipse OpenRPG.
+
+While it is confusing at first, the model is far superior to other tree referencing systems.  Pre 1.8.0, no node could reference a Grid. The referencing system required the reference to be exact and started at the root. Also, the new model is designed to enable freedom of creation and greater control over the Game Tree.
+
+With the Traipse Game Tree GMs are enabled to reference any data from the Game Tree, no matter where it stands. Players can create fewer nodes and use more of the data with fewer nodes.
+
+EZ_Tree (One Touch Reference):
+(ALPHA!)
+The new EZ_Tree System will help benefit users who do not understand the syntax, nor care to learn.
+
+The EZ_Tree System works from within Lists, Texts, and Grids. In the Design Panel you can push the Reference button and navigate the small gametree that pops up to the node you want. Double click that node and the software will create the most efficient node reference for you.
+
+(ALPHA!) In it's Alpha state, Grids will not work completely. You can reference a grid, but you must add teh cell reference. That is not a design flaw, but a restriction of time constraints.
+
+Developer Note:
+The syntax is the hardest part to understand and I expect to change that in the future. The Core of a more expansive Game Tree model is designed. In Traipse you do not need to give access permissions to a node in order to reference it's entirety, which is what I see with Index and Namespace from OpenRPG Core.
+
+In the OpenRPG Core model your Game Tree has a lot more freedom, but only if you grant it, which I always felt was a design flaw. Comparably, with Traipse you can access any data on the Game Tree, no matter where the location.
+
 This freedom will help with future design and I feel it also frees up the hands of the GM who does not need to Index, un-Index, Namespace, un-Namspace the various creatures he or she may have in a Game Tree.</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,540,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples" module="forms" name="Root Reference" version="1.0">
   <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Root Reference&lt;/b&gt;
@@ -82,12 +90,9 @@
 </nodehandler><nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2" module="containers" name="Group_3" version="1.0">
   <nodehandler class="textctrl_handler" frame="400,400,571,67" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group::Group_2::Group_3" module="forms" name="Child_3" version="1.0">
   <text multiline="1" raw_mode="1" send_button="0">!#Group::Child#!</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="forms" name="Child" version="1.0">
+</nodehandler></nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual::Reference Examples::Group" module="forms" name="Child" version="1.0">
   <text multiline="0" raw_mode="1" send_button="0">Child Node Data</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
+</nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,547,51" icon="grid" map="Traipse OpenRPG::User Manual::Reference Examples" module="rpg_grid" name="Grid" version="1.0">
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell size="147">0</cell>
@@ -102,16 +107,16 @@
     <macro name="" />
   </macros>
 </nodehandler></nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Introduction" version="1.0">
-  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
-
-This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
-
-What is OpenRPG:
-OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
-
-What is Traipse OpenRPG:
-Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
-
+  <text multiline="1" send_button="0">Welcome to Traipse OpenRPG.
+
+This small user manual should help users learn about the details of OpenRPG that are often times obscure.  
+
+What is OpenRPG:
+OpenRPG is a virtual game table software that allows users to connect via a network. The software includes a Map, Chat, and a Game Tree.
+
+What is Traipse OpenRPG:
+Traipse OpenRPG is a fork of the original software that is designed to be easy for users, extremely stable, and really powerful.
+
 Traipse has features that set it apart from all other distributions of OpenRPG. The Traipse Suite includes a powerful Update Manager that makes it easy for new developers to create and share their own fork. The Suite also contains an in house Debug Console so users can see what errors, if any, occur.</text>
 </nodehandler><nodehandler class="textctrl_handler" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using Chat" version="1.0">
   <text multiline="1" send_button="0">The Chat window is a basic HTML Parser. It understands all basic HTML tags including table, td, tr, span, font, to name a few.
@@ -120,112 +125,113 @@
 
 The chat also has Settings in the Chat menu that allow you see a Chat Time Index, Images, or strip the HTML and see raw text.</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Using The Map" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
-The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
-
-When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
-
-Lurker or in the Lobby: You cannot access any map tab or changes it's settings.
-
-Player: You have access to the Miniatures tab and the Whiteboard tab.
-
-GM: You have access to all of the tabs.
-
-The Layers:
-A small description of each of the layers.
-
-Background: You can set an image as the background, an image as a tile, or you can set a color.
-
-Grid: You can change the grid size, lines, turn off the grid snap, and change the grid shape.
-
-Miniatures: You can add new or remove miniatures and change mini properties and labels.
-
-Whiteboard: With the whiteboard you can draw lines or add text to the map.
-
-Fog: The fog layer hides the entire map from the prying eyes of players.
</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
-
-Grid Nodes:
-  Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@!
-The example will return the top left most cell data. The grid understands coordinates like this (Row, Column)
-
-  Grid nodes can reference node data just like any other node can.  With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll.  While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. 
-
-  Here is an example with a 3 x 3 Grid
-Example: !@Grid::([#1d3], [#1d3])@!
-
-The result will be a random event from the grid.
-
-Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52)
-
-List Nodes:
-  List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node.
-
-  For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references.
-
-(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.)
-
-  Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!!
-
-Text Nodes:
-  Text nodes remain little changed.  I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes.
-
-  Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes.
-
-  Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
-
-Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
-
-(Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map)
-
-Reference Types:
-  There are three ways of references node data. A Root Reference, a Child Reference, and a Parent Reference.
-
-Root Reference: 
-  A node reference that starts at the Game Tree. The location of the node must be exact or you will return an Invalid Reference!
-
-A Root Reference uses this syntax:
-!@Node::Child::Data@!
-
-Child Reference: 
-  A node reference syntax that starts by looking at within the current container node. As long as the Child Reference is in the same container as the node, the container can change location and the reference will not be damaged. Child References work from within a PC Sheet node as well.
-
-A Child Reference uses this syntax:
-!!Node::Child::Data!!
-
-Parent Reference:
-  A node reference syntax that starts by looking at the tree map and the reference used, then makes an addendum to the node's map to create a reference.  The Parent Node is used when you want to reference the data in a node that is within a different container. Currently Parent References only work if they are used as a reference within a node.
-
-A Parent Reference uses this syntax:
-!#Node::Child::Data#!
-
-Syntax for Special PC Sheet Nodes:
-  The nodes for the specialized PC Sheets now have a new syntax.
-
-Skills, Saves, and Abilities:
-  Skills, Saves, and Abilities all have a similar referencing syntax.  You can return the base value of each by using the correct syntax.
-
-Examples:
-!@Jonethan::Skill::Jump@! (Returns Jump ranks)
-!@Mikael::Strength@! (Returns Ability Score and Mod)
-!@Draj::Will@! (Returns Will Save and Mod)
-
-(Saves and Abilities have a short hand and a long hand. Abilities can use the three letter abbreviation, while saves short hand are Fort, Ref, and Will)
-
-  You can append Check to check each of these against a 1d20 roll, or you can append Mod to discover the Modifier. The Mod can be useful in other nodes
-
-Combat:
-  You can now reference your attacks easily with the Game Tree.  Using the Attack syntax you can select modifier type, and a weapon to attack with.
-Example: !@Kammen-Pai::Attack::M::Dagger@!
-
-Modifier Type:
-  There are two modifier types Melee (M) or Ranged (R) You will see I added can use the long word or the short hand.
-
-Powers, Spells and Feats:
-  Power, Spells and Feats are hard to sometimes hard to remember, and even harder to code.  The use of the Power, Spell or Feat syntax serves as an emote of what you are doing, as well as a reminder of what your Power, Spell, or Feat does.
-
-Examples: 
-!@Kammen-Pai::Cast::Ray of Frost@!
+  <text multiline="1" raw_mode="0" send_button="0">The Tabs:
+The Map is divided into 7 tabs. They are Background, Grid, Miniatures, Whiteboard, Fog, and General. There are 6 layers to the map, one tab for each layer except General.  
+
+When you select one of the tabs you may access that map layer and it's settings.  You may only select tabs based on your role.
+
+Lurker or in the Lobby: You cannot access any map tab or changes it's settings.
+
+Player: You have access to the Miniatures tab and the Whiteboard tab.
+
+GM: You have access to all of the tabs.
+
+The Layers:
+A small description of each of the layers.
+
+Background: You can set an image as the background, an image as a tile, or you can set a color.
+
+Grid: You can change the grid size, lines, turn off the grid snap, and change the grid shape.
+
+Miniatures: You can add new or remove miniatures and change mini properties and labels.
+
+Whiteboard: With the whiteboard you can draw lines or add text to the map.
+
+Fog: The fog layer hides the entire map from the prying eyes of players.
+</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,452,36" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Gametree Additions &amp; Tips" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  With the new additions to the Game Tree  using nodes has never been easier nor has it ever been more fluid. Included here is a list of the additions to the Game Tree referencing model as well as some tips on how to make the Game Tree work the way it was intended.
+
+Grid Nodes:
+  Grid nodes are now reference-able with the coordinates of the grid. Example: !@Grid::(1,1)@!
+The example will return the top left most cell data. The grid understands coordinates like this (Row, Column)
+
+  Grid nodes can reference node data just like any other node can.  With a new added feature grids are even more useful. By using a new die rolling syntax you can draw just the number of the modified roll.  While this will not pass during game play, you can use it with the grid node to create a random chart. The new die roll syntax is [#XdY]. # works just like q, yet it returns only the modified die result. 
+
+  Here is an example with a 3 x 3 Grid
+Example: !@Grid::([#1d3], [#1d3])@!
+
+The result will be a random event from the grid.
+
+Bonus Node Included: A 52 Card Deck with 4 columns and 13 rows. (4 * 13 = 52)
+
+List Nodes:
+  List nodes now have a check box that allows users to send the content as a macro. List nodes are a prime reference holder because users can place a lot of references into one small node.
+
+  For the best results from a list node my tip to users would be to create a list node and place it next to the character sheet they are using, inside a the PC Sheet. The list will then use the Child Referencing syntax, but the PC Sheet can go anywhere in the tree and the player will have easy access to all the references.
+
+(List Nodes inside a Tool created PC sheet vanish when moved, or I would recommend the list be placed inside these sheets also.)
+
+  Here is an example of a Fortitude save inside the recommended list node: !!Fort::Check!!
+
+Text Nodes:
+  Text nodes remain little changed.  I agree with all the 1.7.1 users who tell me, if it's not broke don't fix it. With that in mind I have some good tips for text nodes.
+
+  Text nodes can be used in conjunction with the new grid features to create random encounters. A GM could place a list of text nodes into a folder and the grid could reference the nodes.
+
+  Text nodes also work great when you need to have story text at hand that you don't want to type out during play.  Create chapters with folder nodes and add the adventure text to different nodes.  You can then use a List Node or a Grid Node to reference the different chapters.
+
+Bonus Node Included: A small book node with 1 Chapter and 3 Parts.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,393,95" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Node Referencing" version="1.0"><text hide_title="0" multiline="1" raw_mode="0" send_button="0">  Traipse node referencing is unlike other distributions of OpenRPG.  The Game Tree mapping is a fluid map that changes with the location of your nodes.  This allows you to create a reference node that will stay with your character sheet, and if you change the location of your character sheet the reference will still work.
+
+(Note: Renaming your node causes problems with the tree mapping until you restart the software. You can just move the node and the software will reset the Game Tree map)
+
+Reference Types:
+  There are three ways of references node data. A Root Reference, a Child Reference, and a Parent Reference.
+
+Root Reference: 
+  A node reference that starts at the Game Tree. The location of the node must be exact or you will return an Invalid Reference!
+
+A Root Reference uses this syntax:
+!@Node::Child::Data@!
+
+Child Reference: 
+  A node reference syntax that starts by looking at within the current container node. As long as the Child Reference is in the same container as the node, the container can change location and the reference will not be damaged. Child References work from within a PC Sheet node as well.
+
+A Child Reference uses this syntax:
+!!Node::Child::Data!!
+
+Parent Reference:
+  A node reference syntax that starts by looking at the tree map and the reference used, then makes an addendum to the node's map to create a reference.  The Parent Node is used when you want to reference the data in a node that is within a different child container of the same parent node. 
+
+A Parent Reference uses this syntax:
+!#Node::Child::Data#!
+
+Syntax for Special PC Sheet Nodes:
+  The nodes for the specialized PC Sheets now have a new syntax.
+
+Skills, Saves, and Abilities:
+  Skills, Saves, and Abilities all have a similar referencing syntax.  You can return the base value of each by using the correct syntax.
+
+Examples:
+!@Jonethan::Skill::Jump@! (Returns Jump ranks)
+!@Mikael::Strength@! (Returns Ability Score and Mod)
+!@Draj::Will@! (Returns Will Save and Mod)
+
+(Saves and Abilities have a short hand and a long hand. Abilities can use the three letter abbreviation, while saves short hand are Fort, Ref, and Will)
+
+  You can append Check to check each of these against a 1d20 roll, or you can append Mod to discover the Modifier. The Mod can be useful in other nodes
+
+Combat:
+  You can now reference your attacks easily with the Game Tree.  Using the Attack syntax you can select modifier type, and a weapon to attack with.
+Example: !@Kammen-Pai::Attack::M::Dagger@!
+
+Modifier Type:
+  There are two modifier types Melee (M) or Ranged (R) You will see I added can use the long word or the short hand.
+
+Powers, Spells and Feats:
+  Power, Spells and Feats are hard to sometimes hard to remember, and even harder to code.  The use of the Power, Spell or Feat syntax serves as an emote of what you are doing, as well as a reminder of what your Power, Spell, or Feat does.
+
+Examples: 
+!@Kammen-Pai::Cast::Ray of Frost@!
 !@Kammen-Pai::Feat::Ability Focus@!</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,310,82" icon="note" map="Traipse OpenRPG::User Manual" module="forms" name="Setting up a Server" version="1.0">
   <text multiline="1" send_button="0">In Traipse starting a server has never been easier.  The setup is as easy as 1., 2., 3
 
@@ -247,12 +253,12 @@
     <link href="http://www.assembla.com/wiki/show/traipse/User_Manual" />
   </nodehandler>
   </nodehandler><nodehandler border="0" class="group_handler" cols="1" icon="goblin" map="Traipse OpenRPG" module="containers" name="Bonus Nodes" version="1.0">
-  <nodehandler class="form_handler" frame="514,464,226,108" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
+  <nodehandler class="form_handler" frame="514,464,307,57" height="600" icon="book" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Book" version="1.0" width="400">
   <nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Book" module="forms" name="Index" version="1.0">
   <list hide_title="0" raw_mode="1" send_button="1" type="1">
-    <option selected="1" value="">!!Chapter 1::Part 1!!</option>
-    <option selected="0" value="">!!Chapter 1::Part 2!!</option>
-    <option selected="0" value="">!!Chapter 1::Part 3!!</option>
+    <option caption="" selected="0" value="">!!Chapter 1::Part 1!!</option>
+    <option caption="" selected="0" value="">!!Chapter 1::Part 2!!</option>
+    <option caption="" selected="1" value="">!!Chapter 1::Part 3!!</option>
   </list>
 </nodehandler><nodehandler class="tabber_handler" frame="400,400,392,45" icon="book" map="Traipse OpenRPG::Bonus Nodes::Book" module="containers" name="Chapter 1" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,543,68" icon="note" map="Traipse OpenRPG::Bonus Nodes::Book::Chapter 1" module="forms" name="Part 1" version="1.0">
   <text multiline="1" raw_mode="0" send_button="1">&lt;br /&gt;
@@ -289,8 +295,8 @@
 </nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,501,72" height="600" icon="orc" map="Traipse OpenRPG::Bonus Nodes" module="forms" name="Encounters" version="1.0" width="400">
   <nodehandler class="listbox_handler" frame="400,153,348,150" icon="gear" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="forms" name="Roll" version="1.0">
   <list raw_mode="1" send_button="1" type="1">
-    <option selected="0" value="">!!Chart::([#1d3],1)!!</option>
-    <option selected="1" value="">!!Chart::([#1d2],2)!!</option>
+    <option caption="" selected="0" value="">!!Chart::([#1d3],1)!!</option>
+    <option caption="" selected="1" value="">!!Chart::([#1d2],2)!!</option>
     </list>
 </nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,0,48" icon="grid" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="rpg_grid" name="Chart" version="1.0">
   <grid autosize="0" border="1">
@@ -309,17 +315,14 @@
   <text multiline="1" send_button="1">Hoot Hoot. It's an owl.</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 2" module="forms" name="Enc 1" version="1.0">
   <text multiline="1" send_button="1">Set 2 Random Encounter.</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 1" version="1.0">
+</nodehandler></nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="knight" map="Traipse OpenRPG::Bonus Nodes::Encounters" module="containers" name="Set 1" version="1.0">
   <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 2" version="1.0">
   <text multiline="1" send_button="1">Dark Elves.  Watch out!</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 3" version="1.0">
   <text multiline="1" send_button="1">Kobolds a plenty.</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Traipse OpenRPG::Bonus Nodes::Encounters::Set 1" module="forms" name="Enc 1" version="1.0">
   <text multiline="1" send_button="1">A Wandering Minotaur</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler></nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler class="file_loader" icon="help" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
+</nodehandler></nodehandler></nodehandler></nodehandler><nodehandler class="file_loader" icon="help" map="Traipse OpenRPG" module="core" name="Load Die Roller Notes" version="1.0">
     <file name="die_roller_notes.xml" />
   </nodehandler>
   <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG" module="containers" name="Templates" status="useful" version="1.0">
@@ -338,10 +341,7 @@
       <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Templates::PC Sheets" module="core" name="Create New d20 Character Tool" version="1.0">
         <file name="d20character.xml" />
       </nodehandler>
-      <group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-    <nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
-      <group_atts border="1" cols="1" />
+      </nodehandler><nodehandler border="1" class="group_handler" cols="1" icon="flask" map="Traipse OpenRPG::Templates" module="containers" name="Nodes" status="useful" version="1.0">
       <nodehandler class="file_loader" icon="note" map="Traipse OpenRPG::Templates::Nodes" module="core" name="Create New Text Box" version="1.0">
         <file name="textctrl.xml" />
       </nodehandler>
@@ -359,7 +359,6 @@
       </nodehandler>
     </nodehandler>
     <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG::Templates" module="containers" name="Containers" status="useful" version="1.0">
-      <group_atts border="1" cols="1" />
       <nodehandler class="file_loader" map="Traipse OpenRPG::Templates::Containers" module="core" name="Create New Folder" version="1.0">
         <file name="group.xml" />
       </nodehandler>
@@ -374,7 +373,6 @@
       </nodehandler>
     </nodehandler>
     <nodehandler border="1" class="group_handler" cols="1" icon="gear" map="Traipse OpenRPG::Templates" module="containers" name="Tools" status="useful" version="1.0">
-      <group_atts border="1" cols="1" />
       <nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Die Macro" version="1.0">
         <file name="die_macro.xml" />
       </nodehandler><nodehandler class="file_loader" icon="gear" map="Traipse OpenRPG::Templates::Tools" module="core" name="Create New Chat Macro" version="1.0">
@@ -389,7 +387,6 @@
       </nodehandler>
   </nodehandler>
   <nodehandler border="1" class="group_handler" cols="1" icon="browser" map="Traipse OpenRPG" module="containers" name="OpenRPG+ Resources" version="1.0">
-    <group_atts border="1" cols="1" />
     <nodehandler class="link_handler" icon="html" map="Traipse OpenRPG::OpenRPG+ Resources" module="forms" name="OpenRPG+ Home Page" version="1.0">
       <link href="http://www.openrpg.com" />
     </nodehandler>
@@ -410,7 +407,6 @@
     </nodehandler>
   </nodehandler>
   <nodehandler border="1" class="group_handler" cols="1" map="Traipse OpenRPG" module="containers" name="Examples (Adventures)" version="1.0">
-    <group_atts border="1" cols="1" />
     <nodehandler class="file_loader" icon="d20" map="Traipse OpenRPG::Examples (Adventures)" module="core" name="Bastion Press d20 Adventure" version="1.0">
       <file name="Bastion_adventure.xml" />
     </nodehandler>
--- a/orpg/templates/nodes/4e_char_sheet.xml	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/templates/nodes/4e_char_sheet.xml	Fri Jan 15 23:01:42 2010 -0600
@@ -1,15 +1,61 @@
-<nodehandler class="tabber_handler" frame="400,400,358,183" icon="tabber" map="Group" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet" module="forms" name="Using the 4e Node" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">Because the GPL absorbs material that uses it, even secondary material .. this node is designed to be as generic as possible.
+<nodehandler class="tabber_handler" frame="808,494,162,44" icon="tabber" map="" module="containers" name="4e PC Sheet" version="1.0"><nodehandler class="tabber_handler" frame="400,400,399,89" icon="tabber" map="4e PC Sheet" module="containers" name="Using the 4e PC Sheet" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Introduction" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This node is designed to be as generic as possible. It should contain the core basics for users to fill out with game information that is specific to their character.
+
+The node is also designed to be organized with speed of use in mind. Since the majority of nodes are inside Tabbers you can easily use the top node and find all of your data inside. In fact, that is how I am writing this.
+
+The node is divided into four main tabbers, a grid, and a form. The four tabbers hold your Utilies, Combat information, Inventory, and any easy to grab Rollers that you want to create.
+
+Quick and Dirty:
+Referencing Nodes: The node is designed to use the Gametree referncing system a lot. You can refernce your level, your tier, your ability mod, your weapon die .. all with a quick trip through the EZ Tree referncing system.  Don't worry if you move your node either.
+
+Roller: This is if you want a simple window which contains all of your rollers. Go into design mode, choose the tab you want, press add, give the roller a label (optional), and then with the Reference button choose the node you want.
+
+Utilities: Here is a quick and dirty guide. If you want to add a new power, create a new Text node with the powers features and add it to the Level Tabber in the Utility of your choice.
+
+Combat: This contains grids so you can reference your weapon dice, armor bonuses, feat bonuses .. and they too can use references so if you change a number the software does the math.
+
+Inventory: You guess it.  It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Rollers" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">Inside the Rollers tab you will find 5 lists. You can use these lists to add new references to nodes.  The Rollers tab is also a Tabber node itself, so you can just double click the Rollers node to get all of your rollers in one window.  You can also edit all of your rollers in one window when you enter into the Design mode of the Rollers tabber.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="General" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This form contains a some text nodes that hold basic information about your character. In some Powers the Level and Tier are used to calculate bonuses. You can reference those nodes to make the math easier</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Abilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Abilities Grid contains the 6 abilities all set at values of 8. The third column is the math calculation for the modifier. You can reference that grid column to assist in your math calculations.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Combat" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">The Combat Tabber contains a number of Grid nodes to assist in your combat calculations. Some grids contain a grid cell called Total.
 
-Explinations on how to use will be included.</text></nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Skills" version="1.0">
+To Hit: The To Hit Bonus. This Grid contains a cell called Total. You can add new rows to the grid when you are granted bonuses and then add those references to the total. 
+
+The default contains a reference to the Str Mod.
+
+Weapons: This is a simple grid that contains a Weapon Name and a Weapon Die. With this grid you can add a reference such as [2!#Combat::Weapons::(2,3)#!] to roll your weapon damage twice
+
+AC Bonus: This Grid contains a cell called Total. You can add new rows to the grid when you are granted bonuses and then add those references to the total. 
+
+Feats: Some feats add bonusus to hit or damage.  When these bonuses are calculated you can add them here and the math easier for you.</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Utilities" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">This Tabber contains a Tabber for At Will, Encounter and Daily.  Each tabber contains a node for levels 0 and 1.  You can add new tabbers when you reach higher levels.
+
+Inside the 0 Level tabber for each Utility there is a text node that contains a an attack roll and a damage roll. 
+
+** I went with this format so users could create their Utility nodes and share with others. The nodes can contain Role Play information as well as attack and damage rolls. Also, the nodes can be completely genric, referencing the Name Text node and still look specific **</text></nodehandler><nodehandler class="textctrl_handler" frame="400,400,336,156" icon="note" map="4e PC Sheet::Using the 4e PC Sheet" module="forms" name="Inventory" version="1.0"><text hide_title="0" multiline="1" raw_mode="1" send_button="0">It's just a node to hold your Inventory
+
+This bears repeating:
+It comes with a Back Pack text node that you can clone to make bags and other containers.</text></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="437,400,373,67" icon="tabber" map="4e PC Sheet" module="containers" name="Rollers" version="1.0"><nodehandler class="listbox_handler" frame="400,400,430,57" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Skills" version="1.0">
         <list raw_mode="1" send_button="1" type="1">
-          <option selected="0" value="0">Climb [1d20+5+!!Abilities::(1,3)!!+(!!General::Level!!/2)]</option>
-          <option selected="1" value="0">Hide [1d20+5+!!Abilities::(2,3)!!+(!!General::Level!!/2)]</option>
-          <option selected="0" value="0">Spot [1d20+5+!!Abilities::(4,3)!!+(!!General::Level!!/2)]</option>
+          <option caption="" selected="1" value="0">Climb [1d20+5+!#Abilities::(1,3)#!+(!#General::Level#!/2)</option>
+          <option caption="" selected="0" value="0">Hide [1d20+5+!#Abilities::(2,3)#!+(!#General::Level#!/2)]</option>
+          <option caption="" selected="0" value="0">Spot [1d20+5+!#Abilities::(4,3)#!+(!#General::Level#!/2)]</option>
         </list>
       </nodehandler>
-      <nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet" module="forms" name="General" version="1.0" width="400">
+      <nodehandler class="listbox_handler" frame="400,400,477,43" icon="gear" map="4e PC Sheet::Rollers" module="forms" name="Attacks" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option caption="Sword Attack" selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(2,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(2,2)#!]</option>
+    <option caption="Mace Attack" selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !#Combat::Weapons::(3,1)#! [1d20+!#Abilities::(1,3)#!] &lt;b&gt;Damage:&lt;/b&gt; [1!#Combat::Weapons::(3,2)#!]</option>
+    <option caption="Uncreated" selected="0" value="">Option Text III</option>
+  </list>
+</nodehandler><nodehandler class="splitter_handler" frame="764,400,9,91" horizontal="0" icon="divider" map="4e PC Sheet::Rollers" module="containers" name="Powers" version="1.0">
+    <nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="At Wills" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option caption="At Will Power" selected="1" value="0">!#Utilities::At Will::0::At Will#!</option></list>
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,236,66" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Encounters" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option caption="Encounter" selected="1" value="0">!#Utilities::Encounter::0::Encounter#!</option></list>
+</nodehandler><nodehandler class="listbox_handler" frame="400,400,470,62" icon="gear" map="4e PC Sheet::Rollers::Powers" module="forms" name="Dailys" version="1.0">
+  <list raw_mode="1" send_button="1" type="1">
+    <option caption="Daily" selected="1" value="0">!#Utilities::Daily::0::Daily#!</option></list>
+</nodehandler></nodehandler></nodehandler><nodehandler class="form_handler" frame="400,400,307,186" height="600" icon="form" map="4e PC Sheet" module="forms" name="General" version="1.0" width="400">
   <nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Name" version="1.0">
-  <text multiline="0" send_button="0">text</text>
+  <text multiline="0" raw_mode="1" send_button="0">text</text>
 </nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Player" version="1.0">
   <text multiline="0" send_button="0">text</text>
 </nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Race" version="1.0">
@@ -17,7 +63,9 @@
 </nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet::General" module="forms" name="Class" version="1.0">
   <text multiline="0" send_button="0">text</text>
 </nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Level" version="1.0">
-  <text multiline="0" raw_mode="1" send_button="0">4</text>
+  <text multiline="0" raw_mode="1" send_button="0">1</text>
+</nodehandler><nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="4e PC Sheet::General" module="forms" name="Tier" version="1.0">
+  <text multiline="0" raw_mode="1" send_button="0">1</text>
 </nodehandler></nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,488,115" icon="grid" map="4e PC Sheet" module="rpg_grid" name="Abilities" version="1.0">
         <grid autosize="1" border="1">
           <row version="1.0">
@@ -48,25 +96,21 @@
         <macros>
           <macro name="" />
         </macros>
-      </nodehandler><nodehandler class="textctrl_handler" icon="note" map="4e PC Sheet" module="forms" name="Inventory" version="1.0">
-  <text multiline="1" raw_mode="0" send_button="0">text</text>
-</nodehandler><nodehandler class="form_handler" frame="400,400,210,87" height="600" icon="form" map="4e PC Sheet" module="forms" name="Combat" version="1.0" width="400">
-  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat" module="containers" name="At Will" version="1.0">
-  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat::At Will" module="containers" name="0" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Combat::At Will::0" module="forms" name="Will Spell" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">!#Combat::Spells::0::Cantrip#!</text>
-</nodehandler><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Combat::At Will::0" module="forms" name="At Will" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="1">&lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
-&lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat" module="containers" name="Spells" version="1.0">
-  <nodehandler border="1" class="group_handler" cols="1" map="4e PC Sheet::Combat::Spells" module="containers" name="0" version="1.0">
-  <nodehandler class="textctrl_handler" frame="400,400,260,70" icon="note" map="4e PC Sheet::Combat::Spells::0" module="forms" name="Cantrip" version="1.0">
-  <text multiline="1" raw_mode="1" send_button="0">/me casts &lt;b&gt;Cantrip:&lt;/b&gt; A great powerful magic has been cast.</text>
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><group_atts border="1" cols="1" />
-</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
+      </nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Combat" version="1.0"><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="To Hit" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell>Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!To Hit::(2,3)!! + !!To Hit::(2,4)!!</cell>
+    </row>
+  <row version="1.0"><cell>BAB</cell><cell>0</cell></row><row version="1.0"><cell>Str Mod</cell><cell>!#Abilities::(1,3)#!</cell></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,269,110" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Weapons" version="1.0">
   <grid autosize="1" border="1">
     <row version="1.0">
       <cell>Weapon</cell>
@@ -80,22 +124,60 @@
   <macros>
     <macro name="" />
   </macros>
-</nodehandler></nodehandler><nodehandler class="listbox_handler" frame="400,400,397,93" icon="gear" map="4e PC Sheet" module="forms" name="At Wills" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option selected="0" value="">!!Combat::At Will::0::At Will!!</option>
-    <option selected="1" value="">!!Combat::At Will::0::Will Spell!!</option>
-    <option selected="0" value="">Option Text III</option>
-  </list>
-</nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Spells" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option selected="1" value="">/me casts &lt;b&gt;Spell:&lt;/b&gt; !!Combat::Spells::0::Cantrip!!</option>
-    <option selected="0" value="">Option Text II</option>
-    <option selected="0" value="">Option Text III</option>
-  </list>
-</nodehandler><nodehandler class="listbox_handler" frame="400,400,0,48" icon="gear" map="4e PC Sheet" module="forms" name="Attacks" version="1.0">
-  <list raw_mode="1" send_button="1" type="1">
-    <option selected="0" value="">&lt;b&gt;Attack&lt;/b&gt; !!Combat::Weapons::(2,1)!! [1d20+!!Abilities::(1,3)!!] &lt;b&gt;Damage:&lt;/b&gt; [1!!Combat::Weapons::(2,2)!!]</option>
-    <option selected="1" value="">&lt;b&gt;Attack&lt;/b&gt; !!Combat::Weapons::(3,1)!! [1d20+!!Abilities::(1,3)!!] &lt;b&gt;Damage:&lt;/b&gt; [1!!Combat::Weapons::(3,2)!!]</option>
-    <option selected="0" value="">Option Text III</option>
-  </list>
-</nodehandler></nodehandler>
\ No newline at end of file
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="AC Bonus" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell>Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!AC Bonus::(2,3)!!</cell>
+    </row>
+  <row version="1.0"><cell>Misc</cell><cell>0</cell></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Armor" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell>Bonus</cell>
+    </row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!Armor::(2,3)!!</cell>
+    </row>
+  <row version="1.0"><cell>Base</cell><cell>10</cell></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler><nodehandler class="rpg_grid_handler" frame="400,400,354,98" icon="grid" map="4e PC Sheet::Combat" module="rpg_grid" name="Feats" version="1.0">
+  <grid autosize="1" border="1">
+    <row version="1.0">
+      <cell>Armor</cell>
+      <cell>Bonus</cell>
+    <cell>Descripton</cell></row>
+    <row version="1.0">
+      <cell>Total</cell>
+      <cell>!!Feats(2,3)!!</cell>
+    <cell /></row>
+  <row version="1.0"><cell>Feat</cell><cell>0</cell><cell /></row></grid>
+  <macros>
+    <macro name="" />
+  </macros>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,407,67" icon="tabber" map="4e PC Sheet" module="containers" name="Utilities" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="At Will" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::At Will::0" module="forms" name="At Will" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">/me uses an At Will
+&lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
+&lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::At Will" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Encounter" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Encounter::0" module="forms" name="Encounter" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">/me uses an Encounter
+&lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
+&lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Encounter" module="containers" name="1" version="1.0" /></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet::Utilities" module="containers" name="Daily" version="1.0"><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="0" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,426,47" icon="note" map="4e PC Sheet::Utilities::Daily::0" module="forms" name="Daily" version="1.0">
+  <text multiline="1" raw_mode="1" send_button="1">/me uses an Daily
+&lt;b&gt;Attack:&lt;/b&gt; [1d20+2+!#Abilities::(2,3)#!] 
+&lt;b&gt;Damage:&lt;/b&gt; [2!#Combat::Weapons::(2,2)#!]</text>
+</nodehandler></nodehandler><nodehandler class="tabber_handler" icon="tabber" map="4e PC Sheet::Utilities::Daily" module="containers" name="1" version="1.0" /></nodehandler></nodehandler><nodehandler class="tabber_handler" frame="400,400,9,91" icon="tabber" map="4e PC Sheet" module="containers" name="Inventory" version="1.0"><nodehandler class="textctrl_handler" frame="400,400,115,115" icon="note" map="4e PC Sheet::Inventory" module="forms" name="Back Pack" version="1.0">
+  <text multiline="1" raw_mode="0" send_button="0">Empty.</text>
+</nodehandler></nodehandler></nodehandler>
\ No newline at end of file
--- a/orpg/templates/nodes/die_roller_notes.xml	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/templates/nodes/die_roller_notes.xml	Fri Jan 15 23:01:42 2010 -0600
@@ -1,4 +1,4 @@
-<nodehandler class="tabber_handler" frame="987,495,14,101" icon="tabber" module="containers" name="Die Roller Notes" version="1.0">
+<nodehandler class="tabber_handler" frame="987,495,14,101" icon="tabber" map="" module="containers" name="Die Roller Notes" version="1.0">
   <nodehandler class="textctrl_handler" icon="note" map="Die Roller Notes" module="forms" name="Basics" version="1.0">
     <text multiline="1" send_button="1">The new dieroller is design with expansion in mind. While there are a number of new dieroller options in the base roller, the new design facilitates the building of new rollers that can be loaded at any time.  In this test build three are 3 rollers: std, d20, and wod.  The std roller is the generic roller.  It has generic dice options and is the base for all other dierollers. The d20 and wod rollers are game specific rollers and have game specific options.  They also serve as examples for how to create your own rollers in python.
 
@@ -52,7 +52,7 @@
 </text>
   </nodehandler>
   <nodehandler class="textctrl_handler" frame="400,400,0,48" icon="note" map="Die Roller Notes" module="forms" name="7th Sea" version="1.0">
-    <text multiline="1" send_button="1">The 7th Sea roller is part of the Standard rollers in Traipse.
+    <text multiline="1" send_button="1">Remember, to use the 7th Sea roller type: "/dieroller 7sea"
 
 The 7th Sea roller includes a truncated version that allows you to roll quickly.
 
@@ -71,7 +71,7 @@
 </text>
   </nodehandler>
   <nodehandler class="textctrl_handler" icon="note" map="Die Roller Notes" module="forms" name="WoD roller" version="1.0">
-    <text multiline="1" send_button="1">Remember, to use the wod roller type: "/dieroller wod"
+    <text multiline="1" send_button="1">Remember, to use the WoD roller type: "/dieroller wod"
 
 vs(target) - vs roll against target
 
@@ -98,7 +98,7 @@
 'w' = Wound
 'm' = Mortal</text>
   </nodehandler><nodehandler class="textctrl_handler" icon="note" map="Die Roller Notes" module="forms" name="Mythos roller" version="1.0">
-    <text multiline="1" send_button="1">Remember, to use the mythos roller type: "/dieroller mythos"
+    <text multiline="1" send_button="1">Remember, to use the Mythos roller type: "/dieroller mythos"
 
 The mythos roller is a roller designed by community request. The roller uses a new style of versus similar to the wod roller.
 
@@ -117,8 +117,26 @@
 The mythos roller also works with the new shortened vs. roll
 
 [3v3] = [3d12.vs(3)] - vs roll against 3, 6, 9, 12</text>
+  </nodehandler><nodehandler class="textctrl_handler" frame="400,400,308,51" icon="note" map="Die Roller Notes" module="forms" name="Warhammer FRPG" version="1.0">
+    <text multiline="1" send_button="0">Remember, to use the Warhammer FRPG roller type: "/dieroller wfrpg"
+
+*Special thanks goes to Puu-san who purchase a support ticket for this awesome die roller. Be sure and thank Puu-san.*
+
+The Warhammer FRPG die roller is the first of it's kind and is used when playing the Warhammer Fantasy Role-Playing Game. Unlike standard dice the WFRPG roller has pictures on it's facets. When rolling the WFRPG die, you will return text that corrosponds to the facet one the die.
+
+Die Types &amp; Syntax:
+
+Below you will see the die types and how to roll 1 of each die type.
+
+Reckless:               [1rec]
+Conservative:       [1con]
+Characteristic:      [1cha]
+Challenge:             [1chr]
+Fortune:                [1for]
+Mistfortune:         [1mis]
+Expertise:             [1exp]</text>
   </nodehandler><nodehandler class="textctrl_handler" frame="400,400,308,51" icon="note" map="Die Roller Notes" module="forms" name="Hero Roller" version="1.0">
-    <text multiline="1" send_button="0">Remember, to use the hero roller type: "/dieroller hero"
+    <text multiline="1" send_button="0">Remember, to use the Hero roller type: "/dieroller hero"
 
 Skill Roller, example [3d6.sk(11,0)]
 Make a SKill roll.  The first number of the two modifiers is the rating in the skill, 11 meaning 11 or less.  The second number is any penalty or bonus you have for the roll.  A positive number is a bonus, a negative number is a penalty.  As with many Hero system rolls, the only die choice that makes sense is 3d6
--- a/orpg/tools/orpg_settings.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/tools/orpg_settings.py	Fri Jan 15 23:01:42 2010 -0600
@@ -129,7 +129,6 @@
 
         for i in xrange(0,len(self.changes)):
             self.settings.set_setting(self.changes[i][0], self.changes[i][1])
-            top_frame = component.get('frame')
 
             ## Settings are now reactive and organized ##
             ok = {'IdleStatusAlias': self.chat.chat_cmds.on_status,
@@ -186,13 +185,15 @@
         rm = component.get('DiceManager')
         try:
             rm.setRoller(changes)
-            self.chat.SystemPost('You have changed your die roller to the <b>"' + rm.getRoller.name + '"</b> roller.')
-        except:
+            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>')
 
     def colortree_ok(self, changes):
+        top_frame = component.get('frame')
         if changes == '1':
             top_frame.tree.SetBackgroundColour(self.settings.get_setting('bgcolor'))
             top_frame.tree.SetForegroundColour(self.settings.get_setting('textcolor'))
@@ -219,6 +220,7 @@
     def text_ok(self, changes):
         self.chat.chatwnd.SetPage(self.chat.ResetPage())
         self.chat.chatwnd.scroll_down()
+        top_frame = component.get('frame')
         if self.settings.get_setting('ColorTree') == '1':
             top_frame.tree.SetBackgroundColour(self.settings.get_setting('bgcolor'))
             top_frame.tree.SetForegroundColour(self.settings.get_setting('textcolor'))
--- a/orpg/tools/predTextCtrl.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/orpg/tools/predTextCtrl.py	Fri Jan 15 23:01:42 2010 -0600
@@ -311,7 +311,7 @@
     # Purpose:  Constructor for predTextCtrl.  Calls wx.TextCtrl.__init__ to get default init
     #           behavior and then inits a LetterTree and captures the parent for later use in
     #           passing events up the chain.
-    def __init__(self, parent, id = -1, value = "" , size = wx.DefaultSize, style = 0, name = "text",keyHook = None, validator=None):
+    def __init__(self, parent, id = -1, value = "", size = (30,30), style = 0, name = "text", keyHook = None, validator=None):
 
         #  Call super() for default behavior
         if validator:
@@ -319,6 +319,7 @@
         else:
             ExpandoTextCtrl.__init__(self, parent, id=id, value=value, size=size, style=style, name=name)
 
+
         self.tree = LetterTree      #  Instantiate a new LetterTree.
         #  TODO:  make name of word file an argument.
         self.parent = parent           #  Save parent for later use in passing KeyEvents
@@ -427,27 +428,23 @@
                                                            #  clobber the prediction.
 
                     return                                 #  Don't pass tab on in this case
-            elif event.GetKeyCode() == wx.WXK_RETURN and event.ShiftDown():
-                logger.exception('Shift + Enter Not completed, 439, predtextCtrl', True)
-                st = self.GetValue()
-                st += '<br />'
-                return
 
-            elif event.GetKeyCode() == wx.WXK_RETURN:            #  We want to hook returns, so that we can update the word list
+            elif event.GetKeyCode() == wx.WXK_RETURN:      #  We want to hook returns, so that we can update the word list
                 st = self.GetValue()                       #  Grab the text from the control
                 newSt = ""                                 #  Init a buffer
                 #  This block of code, by popular demand, changes the behavior of the control to ignore any prediction that
-                #    hasn't been "accepted" when the enter key is struck.
-                (startSel,endSel) = self.GetSelection()                 #  get the curren selection
+                #  hasn't been "accepted" when the enter key is struck.
+                (startSel,endSel) = self.GetSelection()    #  get the curren selection
 
                 #
                 # Start update
                 # Changed the following to allow for more friendly behavior in
                 # a multilined predTextCtrl.
                 #
-                # front = st[:startSel]                                   #  Slice off the text to the front of where we are
-                # back = st[endSel:]                                      #  Slice off the text to the end from where we are
-                # st = front + back                          #  This expression creates a string that get rid of any selected text.
+                # front = st[:startSel]                      #  Slice off the text to the front of where we are
+                # back = st[endSel:]                         #  Slice off the text to the end from where we are
+                # st = front + back                          #  This expression creates a string that get rid 
+                                                             #  of any selected text.
                 # self.SetValue(st)
 
                 self.Remove( startSel, endSel )
@@ -470,8 +467,7 @@
                 #  new ones
                 for aWord in string.split(newSt):
                     self.tree.incWord(string.lower(aWord))
-
-                self.parent.OnChar(event)                   #  Now that all of the words are added, pass the event and return
+                self.parent.OnChar(event) #  Now that all of the words are added, pass the event and return
                 return
 
             #  We want to capture the right arrow key to fix a slight UI bug that occurs when one right arrows
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/xxminiquicknote.py	Fri Jan 15 23:01:42 2010 -0600
@@ -0,0 +1,74 @@
+import os
+import orpg.pluginhandler
+from orpg.mapper.miniatures_handler import *
+from orpg.orpgCore import *
+import wx
+
+
+class QuickNoteDialog(wx.Dialog):
+    def __init__(self):
+        wx.Dialog.__init__(self, None, -1, "Quick Note", size=(250, 210))
+        self.text = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.text, 1, wx.EXPAND)
+        self.SetSizer(sizer)
+
+class Plugin(orpg.pluginhandler.PluginHandler):
+    def __init__(self, plugindb, parent):
+        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
+        self.name = 'Mini Quick Notes'
+        self.author = 'David'
+        self.help = """Allows you to add private notes when you right-click on a mini on the map.
+
+Note: it will try to save data between sessions but you must load plugin AFTER the map has been loaded
+so do not auto-load this plugin.  Also these notes are NOT shared with other users.
+
+Look at the mini superscript plugin for an example of how to do that.
+
+Modified for Traipse (Prof. Ebral)
+EXPERIMENTAL! In the process of being updated."""
+        self.save_on_exit = False;
+
+    def plugin_menu(self):
+        pass
+        
+    def plugin_enabled(self):
+        m = component.get("map").layer_handlers[2]
+        m.set_mini_rclick_menu_item("Quick Notes", self.on_quick_note)
+
+        db_notes_list = self.plugindb.GetList("xxminiquicknote", "notes", [])
+        matched = 0;
+        for mini in component.get("map").canvas.layers['miniatures'].miniatures:
+            print 'label:'+mini.label
+            print 'posx:'+str(mini.pos.x)
+            print 'posy:'+str(mini.pos.y)
+            for db_note in db_notes_list:
+                print 'db_note:'+str(db_note)
+                if mini.label == db_note[0] and mini.pos.x == db_note[1] and mini.pos.y == db_note[2]:
+                    mini.quicknote = db_note[3]
+                    db_notes_list.remove(db_note)
+                    matched += 1
+                    break
+
+    def plugin_disabled(self):
+        m = component.get("map").layer_handlers[2]
+        m.set_mini_rclick_menu_item("Quick Notes", None)
+
+        if self.save_on_exit:
+            db_notes_list = []
+            for mini in component.get("map").canvas.layers['miniatures'].miniatures:
+                if 'quicknote' in mini.__dict__:
+                    db_notes_list.append([mini.label, mini.pos.x, mini.pos.y, mini.quicknote])
+            self.plugindb.SetList("xxminiquicknote", "notes", db_notes_list)
+
+    def on_quick_note(self, event):
+        self.save_on_exit = True
+        m = component.get("map").layer_handlers[2]
+        # m.sel_rmin is the mini that was just right-clicked
+        if 'quicknote' not in m.sel_rmin.__dict__:
+            m.sel_rmin.quicknote = ''
+        dlg = QuickNoteDialog()
+        dlg.text.SetValue(m.sel_rmin.quicknote)
+        dlg.ShowModal()
+        m.sel_rmin.quicknote = dlg.text.GetValue()
+        dlg.Destroy()
--- a/upmana/updatemana.py	Thu Dec 10 23:16:08 2009 -0600
+++ b/upmana/updatemana.py	Fri Jan 15 23:01:42 2010 -0600
@@ -5,7 +5,6 @@
 from orpg.orpgCore import component
 from orpg.dirpath import dir_struct
 from orpg.tools.orpg_log import logger, crash
-from orpg.tools.decorators import debugging
 from upmana.validate import validate
 from orpg.dirpath import dir_struct
 from mercurial import ui, hg, commands, repo, revlog, cmdutil, util
@@ -18,7 +17,6 @@
         sys.__stdout__.write(text)
 
 class Updater(wx.Panel):
-    @debugging
     def __init__(self, parent, component):
         wx.Panel.__init__(self, parent)
         ### Status Bar ###
@@ -57,7 +55,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['finish'].Disable()
         self.sizer.AddGrowableCol(0)
         self.sizer.AddGrowableRow(0)
         self.SetSizer(self.sizer)
@@ -131,9 +129,9 @@
         ignore.close()
 
     def Finish(self, evt=None):
-        try: self.parent.Destroy()
-        except:
-            print 'Fail'; exit()
+        try: component.get('upmana-win').OnClose(None)
+        except Exception, e:
+            print 'Fail', e; exit()
 
     def ChooseBranch(self, evt=None):
         dlg = wx.Dialog(self, wx.ID_ANY, "Package Selector", style=wx.DEFAULT_DIALOG_STYLE)
@@ -715,6 +713,7 @@
         p.Layout()
         self.Refresh()
         self.Bind(wx.EVT_CLOSE, self.OnClose)
+        component.add('upmana-win', self)
 
     def OnClose(self, event):
         if self.main == False: self.Destroy()