comparison orpg/chat/chatwnd.py @ 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 ff48c2741fe7
children dcae32e219f1
comparison
equal deleted inserted replaced
172:8834425a85b0 183:0d9b746b5751
166 self.menu = wx.Menu() 166 self.menu = wx.Menu()
167 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy") 167 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy")
168 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item) 168 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item)
169 self.menu.AppendItem(item) 169 self.menu.AppendItem(item)
170 170
171
172 def OnM_EditCopy(self, evt): 171 def OnM_EditCopy(self, evt):
173 wx.TheClipboard.UsePrimarySelection(False) 172 wx.TheClipboard.UsePrimarySelection(False)
174 wx.TheClipboard.Open() 173 wx.TheClipboard.Open()
175 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText())) 174 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText()))
176 wx.TheClipboard.Close() 175 wx.TheClipboard.Close()
522 self.parsed=0 521 self.parsed=0
523 #chat commands 522 #chat commands
524 self.lockscroll = False # set the default to scrolling on. 523 self.lockscroll = False # set the default to scrolling on.
525 self.chat_cmds = commands.chat_commands(self) 524 self.chat_cmds = commands.chat_commands(self)
526 self.html_strip = strip_html 525 self.html_strip = strip_html
526 self.f_keys = {wx.WXK_F1: 'event.GetKeyCode() == wx.WXK_F1', wx.WXK_F2: 'event.GetKeyCode() == wx.WXK_F2',
527 wx.WXK_F3: 'event.GetKeyCode() == wx.WXK_F3', wx.WXK_F4: 'event.GetKeyCode() == wx.WXK_F4',
528 wx.WXK_F5: 'event.GetKeyCode() == wx.WXK_F5', wx.WXK_F6: 'event.GetKeyCode() == wx.WXK_F6',
529 wx.WXK_F7: 'event.GetKeyCode() == wx.WXK_F7', wx.WXK_F8: 'event.GetKeyCode() == wx.WXK_F8',
530 wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10',
531 wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'}
527 #Alias Lib stuff 532 #Alias Lib stuff
528 self.defaultAliasName = 'Use Real Name' 533 self.defaultAliasName = 'Use Real Name'
529 self.defaultFilterName = 'No Filter' 534 self.defaultFilterName = 'No Filter'
530 self.advancedFilter = False 535 self.advancedFilter = False
531 self.lastSend = 0 # this is used to help implement the player typing indicator 536 self.lastSend = 0 # this is used to help implement the player typing indicator
829 self.dieIDs[self.d100Button.GetId()] = 'd100' 834 self.dieIDs[self.d100Button.GetId()] = 'd100'
830 self.Bind(wx.EVT_BUTTON, self.pop_textpop, self.textpop_lock) 835 self.Bind(wx.EVT_BUTTON, self.pop_textpop, self.textpop_lock)
831 self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock) 836 self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock)
832 self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel) 837 self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel)
833 self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar) 838 self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar)
839 self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down)
834 self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy) 840 self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy)
835 # def build_ctrls - end 841 # def build_ctrls - end
836 842
837 def build_bar(self): 843 def build_bar(self):
838 self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) 844 self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
1090 # !self : instance of self 1096 # !self : instance of self
1091 # !event : 1097 # !event :
1092 # 1098 #
1093 # Note: self.chattxt now handles it's own Key events. It does, however still 1099 # Note: self.chattxt now handles it's own Key events. It does, however still
1094 # call it's parent's (self) OnChar to handle "default" behavior. 1100 # call it's parent's (self) OnChar to handle "default" behavior.
1101
1102 def submit_chat_text(self, s):
1103 self.histidx = -1
1104 self.temptext = ""
1105 self.history = [s] + self.history
1106 #if not len(macroText): self.chattxt.SetValue("")
1107
1108 # play sound
1109 sound_file = self.settings.get_setting("SendSound")
1110 if sound_file != '': component.get('sound').play(sound_file)
1111 if s[0] != "/": ## it's not a slash command
1112 s = self.ParsePost( s, True, True )
1113 else: self.chat_cmds.docmd(s) # emote is in chatutils.py
1114
1115 def on_chat_key_down(self, event):
1116 s = self.chattxt.GetValue()
1117 if event.GetKeyCode() == wx.WXK_RETURN and not event.ShiftDown():
1118 logger.debug("event.GetKeyCode() == wx.WXK_RETURN")
1119 self.set_colors()
1120 if self.session.get_status() == MPLAY_CONNECTED:
1121 self.sendTyping(0)
1122 if len(s):
1123 self.chattxt.SetValue('')
1124 s = s.replace('\n', '<br />')
1125 self.submit_chat_text(s)
1126 return
1127 event.Skip()
1095 1128
1096 def OnChar(self, event): 1129 def OnChar(self, event):
1097 s = self.chattxt.GetValue() 1130 s = self.chattxt.GetValue()
1098 #self.histlen = len(self.history) - 1 1131
1099 1132 macroText = ""
1100 ## RETURN KEY (no matter if there is text in chattxt) 1133 s_key = False
1101 # This section is run even if there is nothing in the chattxt (as opposed to the next wx.WXK_RETURN handler 1134 if self.f_keys.has_key(event.GetKeyCode()): s_key = self.f_keys[event.GetKeyCode()]
1102 if event.GetKeyCode() == wx.WXK_RETURN: 1135
1103 logger.debug("event.GetKeyCode() == wx.WXK_RETURN") 1136 if s_key: macroText = settings.get(s_key[29:])
1104 self.set_colors()
1105 if self.session.get_status() == MPLAY_CONNECTED: # only do if we're connected
1106 self.sendTyping(0) # Send a "not_typing" event on enter key press
1107 macroText=""
1108 recycle_bin = {wx.WXK_F1: 'event.GetKeyCode() == wx.WXK_F1', wx.WXK_F2: 'event.GetKeyCode() == wx.WXK_F2',
1109 wx.WXK_F3: 'event.GetKeyCode() == wx.WXK_F3', wx.WXK_F4: 'event.GetKeyCode() == wx.WXK_F4',
1110 wx.WXK_F5: 'event.GetKeyCode() == wx.WXK_F5', wx.WXK_F6: 'event.GetKeyCode() == wx.WXK_F6',
1111 wx.WXK_F7: 'event.GetKeyCode() == wx.WXK_F7', wx.WXK_F8: 'event.GetKeyCode() == wx.WXK_F8',
1112 wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10',
1113 wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'}
1114
1115 bin_event = event.GetKeyCode()
1116 if recycle_bin.has_key(bin_event):
1117 logger.debug(lambda bin_event: recycle_bin[bin_event])
1118 macroText = self.settings.get_setting(recycle_bin[bin_event][29:])
1119 recycle_bin = {}; del bin_event
1120 1137
1121 # Append to the existing typed text as needed and make sure the status doesn't change back. 1138 # Append to the existing typed text as needed and make sure the status doesn't change back.
1122 if len(macroText): 1139 if len(macroText):
1123 self.sendTyping(0) 1140 self.sendTyping(0)
1124 s = macroText 1141 self.submit_chat_text(macroText)
1125
1126 ## RETURN KEY (and not text in control)
1127 if (event.GetKeyCode() == wx.WXK_RETURN and len(s)) or len(macroText):
1128 logger.debug("(event.GetKeyCode() == wx.WXK_RETURN and len(s)) or len(macroText)")
1129 self.histidx = -1
1130 self.temptext = ""
1131 self.history = [s] + self.history#prepended instead of appended now, so higher index = greater age
1132 if not len(macroText): self.chattxt.SetValue("")
1133 # play sound
1134 sound_file = self.settings.get_setting("SendSound")
1135 if sound_file != '': component.get('sound').play(sound_file)
1136 if s[0] != "/": ## it's not a slash command
1137 s = self.ParsePost( s, True, True )
1138 else: self.chat_cmds.docmd(s) # emote is in chatutils.py
1139 1142
1140 ## UP KEY 1143 ## UP KEY
1141 elif event.GetKeyCode() == wx.WXK_UP: 1144 elif event.GetKeyCode() == wx.WXK_UP:
1142 logger.debug("event.GetKeyCode() == wx.WXK_UP") 1145 logger.debug("event.GetKeyCode() == wx.WXK_UP")
1143 if self.histidx < len(self.history)-1: 1146 if self.histidx < len(self.history)-1:
1225 logger.debug("event.GetKeyCode() == wx.WXK_END") 1228 logger.debug("event.GetKeyCode() == wx.WXK_END")
1226 if self.lockscroll: 1229 if self.lockscroll:
1227 self.lock_scroll(0) 1230 self.lock_scroll(0)
1228 self.Post() 1231 self.Post()
1229 event.Skip() 1232 event.Skip()
1233
1234 elif event.GetKeyCode() == wx.WXK_RETURN and event.ShiftDown():
1235 st = self.chattxt.GetValue().split('\x0b')
1236 st += '\n'
1237 i = self.chattxt.GetInsertionPoint()
1238 self.chattxt.SetValue(''.join(st))
1239 self.chattxt.SetInsertionPoint(i+1)
1240 return
1230 1241
1231 ## NOTHING 1242 ## NOTHING
1232 else: event.Skip() 1243 else: event.Skip()
1233 logger.debug("Exit chat_panel->OnChar(self, event)") 1244 logger.debug("Exit chat_panel->OnChar(self, event)")
1234 # def OnChar - end 1245 # def OnChar - end
1858 i += 1 1869 i += 1
1859 return rs 1870 return rs
1860 1871
1861 def resolve_loop(self, node, path, step, depth): 1872 def resolve_loop(self, node, path, step, depth):
1862 if step == depth: 1873 if step == depth:
1863 self.resolution(node) 1874 return self.resolution(node)
1864 else: 1875 else:
1865 child_list = node.findall('nodehandler') 1876 child_list = node.findall('nodehandler')
1866 for child in child_list: 1877 for child in child_list:
1867 if step == depth: break 1878 if step == depth: break
1868 if child.get('name') == path[step]: 1879 if child.get('name') == path[step]:
1869 node = child 1880 node = child
1870 step += 1 1881 step += 1
1871 if node.get('class') in ('dnd35char_handler', "SWd20char_handler", "d20char_handler", "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth) 1882 if node.get('class') in ('dnd35char_handler',
1883 "SWd20char_handler",
1884 "d20char_handler",
1885 "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth)
1872 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth) 1886 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth)
1873 else: self.resolve_loop(node, path, step, depth) 1887 else: self.resolve_loop(node, path, step, depth)
1874
1875 1888
1876 def resolve_grid(self, node, path, step, depth): 1889 def resolve_grid(self, node, path, step, depth):
1877 if step == depth: 1890 if step == depth:
1878 self.data = 'Invalid Grid Reference!' 1891 self.data = 'Invalid Grid Reference!'
1879 return 1892 return
1883 col = rows[int(self.ParseDice(cell[0]))-1].findall('cell') 1896 col = rows[int(self.ParseDice(cell[0]))-1].findall('cell')
1884 try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data' 1897 try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data'
1885 except: self.data = 'Invalid Grid Reference!' 1898 except: self.data = 'Invalid Grid Reference!'
1886 return 1899 return
1887 1900
1901 def resolution(self, node):
1902 if self.passed == False:
1903 self.passed = True
1904 if node.get('class') == 'textctrl_handler':
1905 s = str(node.find('text').text)
1906 else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
1907 else:
1908 s = ''
1909 s = self.ParseMap(s, node)
1910 s = self.ParseParent(s, node.get('map'))
1911 self.data = s
1912
1913 def ParseMap(self, s, node):
1914 """Parses player input for embedded nodes rolls"""
1915 cur_loc = 0
1916 reg = re.compile("(!!(.*?)!!)")
1917 matches = reg.findall(s)
1918 for i in xrange(0,len(matches)):
1919 tree_map = node.get('map')
1920 tree_map = tree_map + '::' + matches[i][1]
1921 newstr = '!@'+ tree_map +'@!'
1922 s = s.replace(matches[i][0], newstr, 1)
1923 s = self.ParseNode(s)
1924 s = self.ParseParent(s, tree_map)
1925 return s
1926
1927 def ParseParent(self, s, tree_map):
1928 """Parses player input for embedded nodes rolls"""
1929 cur_loc = 0
1930 reg = re.compile("(!#(.*?)#!)")
1931 matches = reg.findall(s)
1932 for i in xrange(0,len(matches)):
1933 ## Build the new tree_map
1934 new_map = tree_map.split('::')
1935 del new_map[len(new_map)-1]
1936 parent_map = matches[i][1].split('::')
1937 ## Find an index or use 1 for ease of use.
1938 try: index = new_map.index(parent_map[0])
1939 except: index = 1
1940 ## Just replace the old tree_map from the index.
1941 new_map[index:len(new_map)] = parent_map
1942 newstr = '::'.join(new_map)
1943 newstr = '!@'+ newstr +'@!'
1944 s = s.replace(matches[i][0], newstr, 1)
1945 #s = self.ParseMap(s, node) ## Needs to be added
1946 s = self.ParseNode(s)
1947 return s
1948
1949 def resolve_nodes(self, s):
1950 self.passed = False
1951 self.data = 'Invalid Reference!'
1952 value = ""
1953 path = s.split('::')
1954 depth = len(path)
1955 self.gametree = component.get('tree')
1956 try: node = self.gametree.tree_map[path[0]]['node']
1957 except Exception, e: return self.data
1958 if node.get('class') in ('dnd35char_handler',
1959 "SWd20char_handler",
1960 "d20char_handler",
1961 "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
1962 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
1963 else: self.resolve_loop(node, path, 1, depth)
1964 return self.data
1965
1888 def resolve_cust_loop(self, node, path, step, depth): 1966 def resolve_cust_loop(self, node, path, step, depth):
1889 node_class = node.get('class') 1967 node_class = node.get('class')
1890 ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ## 1968 ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
1891 if step == depth: self.resolution(node) 1969 if step == depth: self.resolution(node)
1892 ##Build Abilities dictionary## 1970 ##Build Abilities dictionary##
1904 1982
1905 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves') 1983 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
1906 else: ab = node.find('saves') 1984 else: ab = node.find('saves')
1907 ab_list = ab.findall('save') 1985 ab_list = ab.findall('save')
1908 for save in ab_list: 1986 for save in ab_list:
1909 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]) ) ) 1987 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]) ) )
1910 if save.get('name') == 'Fortitude': abbr = 'Fort' 1988 if save.get('name') == 'Fortitude': abbr = 'Fort'
1911 if save.get('name') == 'Reflex': abbr = 'Ref' 1989 if save.get('name') == 'Reflex': abbr = 'Ref'
1912 if save.get('name') == 'Will': abbr = 'Will' 1990 if save.get('name') == 'Will': abbr = 'Will'
1913 pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) ) 1991 pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
1914 1992
1965 elif pc_stats.has_key(path[step].title()): 2043 elif pc_stats.has_key(path[step].title()):
1966 if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')' 2044 if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
1967 elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1] 2045 elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1]
1968 elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']' 2046 elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']'
1969 return 2047 return
1970
1971 def resolution(self, node):
1972 if self.passed == False:
1973 self.passed = True
1974 if node.get('class') == 'textctrl_handler': self.data = str(node.find('text').text)
1975 else: self.data = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!'
1976 else:
1977 self.data = ''
1978 pass
1979 self.data = self.ParseMap(self.data, node)
1980
1981 def ParseMap(self, s, node):
1982 """Parses player input for embedded nodes rolls"""
1983 cur_loc = 0
1984 reg = re.compile("(!!(.*?)!!)")
1985 matches = reg.findall(s)
1986 for i in xrange(0,len(matches)):
1987 tree_map = node.get('map') + '::' + matches[i][1]
1988 newstr = '!@'+ tree_map +'@!'
1989 s = s.replace(matches[i][0], newstr, 1)
1990 s = self.ParseNode(s)
1991 s = self.ParseParent(s, tree_map)
1992 return s
1993
1994 def ParseParent(self, s, tree_map):
1995 """Parses player input for embedded nodes rolls"""
1996 cur_loc = 0
1997 reg = re.compile("(!#(.*?)#!)")
1998 matches = reg.findall(s)
1999 for i in xrange(0,len(matches)):
2000 ## Build the new tree_map
2001 new_map = tree_map.split('::')
2002 del new_map[len(new_map)-1]
2003 parent_map = matches[i][1].split('::')
2004 ## Find an index or use 1 for ease of use.
2005 try: index = new_map.index(parent_map[0])
2006 except: index = 1
2007 ## Just replace the old tree_map from the index.
2008 new_map[index:len(new_map)] = parent_map
2009 newstr = '::'.join(new_map)
2010 newstr = '!@'+ newstr +'@!'
2011 s = s.replace(matches[i][0], newstr, 1)
2012 s = self.ParseNode(s)
2013 return s
2014
2015 def resolve_nodes(self, s):
2016 self.passed = False
2017 self.data = 'Invalid Reference!'
2018 value = ""
2019 path = s.split('::')
2020 depth = len(path)
2021 self.gametree = component.get('tree')
2022 try: node = self.gametree.tree_map[path[0]]['node']
2023 except: return self.data
2024 if node.get('class') in ('dnd35char_handler', "SWd20char_handler", "d20char_handler", "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth)
2025 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth)
2026 else: self.resolve_loop(node, path, 1, depth)
2027 return self.data