comparison orpg/chat/chatwnd.py @ 195:b633f4c64aae alpha

Traipse Alpha 'OpenRPG' {100219-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Patch-2) New Features: New Namespace method with two new syntaxes Fixes: Fix to Server GUI startup errors Fix to Server GUI Rooms tab updating Fix to Chat and Settings if non existant die roller is picked Fix to Dieroller and .open() used with .vs(). Successes are correctly calculated Fix to Alias Lib's Export to Tree, Open, Save features Fix to alias node, now works properly Fix to Splitter node, minor GUI cleanup
author sirebral
date Sat, 24 Apr 2010 08:37:20 -0500
parents 4b2884f29a72
children 0bc44a57ae6c
comparison
equal deleted inserted replaced
182:4b2884f29a72 195:b633f4c64aae
19 # 19 #
20 # File: chatutils.py 20 # File: chatutils.py
21 # Author: Chris Davis 21 # Author: Chris Davis
22 # Maintainer: 22 # Maintainer:
23 # Version: 23 # Version:
24 # $Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $ 24 # $Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
25 # 25 #
26 # Description: This file contains some of the basic definitions for the chat 26 # Description: This file contains some of the basic definitions for the chat
27 # utilities in the orpg project. 27 # utilities in the orpg project.
28 # 28 #
29 # History 29 # History
35 # + Added strip_script_tags() to post() to remove crash point. See chat_util.py 35 # + Added strip_script_tags() to post() to remove crash point. See chat_util.py
36 # 2005-04-25 Snowdog 36 # 2005-04-25 Snowdog
37 # + Added simple_html_repair() to post() to fix malformed html in the chat window 37 # + Added simple_html_repair() to post() to fix malformed html in the chat window
38 # 38 #
39 39
40 __version__ = "$Id: chatwnd.py,v 1.177 2007/12/07 20:39:48 digitalxero Exp $" 40 __version__ = "$Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
41 41
42 42
43 ## 43 ##
44 ## Module Loading 44 ## Module Loading
45 ## 45 ##
46 import os, time, re, sys, traceback, webbrowser, commands, chat_msg, chat_util 46 import os, time, re, sys, traceback, webbrowser, commands, chat_msg, chat_util
47 47
48 from orpg.orpg_version import VERSION 48 from orpg.orpg_version import VERSION, DISTRO, DIS_VER, BUILD
49 from orpg.orpg_windows import * 49 from orpg.orpg_windows import *
50 from orpg.player_list import WG_LIST 50 from orpg.player_list import WG_LIST
51 from orpg.dirpath import dir_struct 51 from orpg.dirpath import dir_struct
52 #from orpg.tools.metamenus import MenuEx #Needed?
53 from string import * 52 from string import *
54 53
55 import cStringIO # for reading inline imagedata as a stream 54 import cStringIO # for reading inline imagedata as a stream
56 from HTMLParser import HTMLParser 55 from HTMLParser import HTMLParser
57 from wx.lib.expando import EVT_ETC_LAYOUT_NEEDED 56 from wx.lib.expando import EVT_ETC_LAYOUT_NEEDED
60 import orpg.tools.inputValidator 59 import orpg.tools.inputValidator
61 from orpg.tools.validate import validate 60 from orpg.tools.validate import validate
62 from orpg.tools.orpg_settings import settings 61 from orpg.tools.orpg_settings import settings
63 import orpg.tools.predTextCtrl 62 import orpg.tools.predTextCtrl
64 from orpg.tools.orpg_log import logger, debug 63 from orpg.tools.orpg_log import logger, debug
64 from orpg.tools.InterParse import Parse
65 from orpg.orpgCore import component 65 from orpg.orpgCore import component
66 from xml.etree.ElementTree import tostring 66 from xml.etree.ElementTree import tostring
67 67
68 from orpg.networking.mplay_client import MPLAY_CONNECTED # needed to only send typing/not_typing messages while connected 68 from orpg.networking.mplay_client import MPLAY_CONNECTED
69
70 NEWCHAT = False 69 NEWCHAT = False
71 try: 70 try:
72 import wx.webview 71 import wx.webview
73 NEWCHAT = True 72 NEWCHAT = True
74 except: pass 73 except: pass
81 80
82 def __init__(self): 81 def __init__(self):
83 self.accum = "" 82 self.accum = ""
84 self.special_tags = ['hr', 'br', 'img'] 83 self.special_tags = ['hr', 'br', 'img']
85 84
86 def handle_data(self, data): # quote cdata literally 85 def handle_data(self, data):
87 self.accum += data 86 self.accum += data
88 87
89 def handle_entityref(self, name): # entities must be preserved exactly 88 def handle_entityref(self, name):
90 self.accum += "&" + name + ";" 89 self.accum += "&" + name + ";"
91 90
92 def handle_starttag(self, tag, attrs): 91 def handle_starttag(self, tag, attrs):
93 if tag in self.special_tags: 92 if tag in self.special_tags:
94 self.accum += '<' + tag 93 self.accum += '<' + tag
95 for attrib in attrs: self.accum += ' ' + attrib[0] + '="' + attrib[1] + '"' 94 for attrib in attrs: self.accum += ' ' + attrib[0] + '="' + attrib[1] + '"'
96 self.accum += '>' 95 self.accum += '>'
97 96
98 def handle_charref(self, name): # charrefs too 97 def handle_charref(self, name):
99 self.accum += "&#" + name + ";" 98 self.accum += "&#" + name + ";"
100 htmlstripper = HTMLStripper() 99 htmlstripper = HTMLStripper()
101 100
102 # utility function; see Post().
103 101
104 def strip_html(string): 102 def strip_html(string):
105 "Return string tripped of html tags." 103 "Return string tripped of html tags."
106 htmlstripper.reset() 104 htmlstripper.reset()
107 htmlstripper.accum = "" 105 htmlstripper.accum = ""
112 110
113 def log( settings, c, text ): 111 def log( settings, c, text ):
114 filename = settings.get_setting('GameLogPrefix') 112 filename = settings.get_setting('GameLogPrefix')
115 if filename > '' and filename[0] != commands.ANTI_LOG_CHAR: 113 if filename > '' and filename[0] != commands.ANTI_LOG_CHAR:
116 filename = filename + time.strftime( '-%Y-%m-%d.html', time.localtime( time.time() ) ) 114 filename = filename + time.strftime( '-%Y-%m-%d.html', time.localtime( time.time() ) )
117 #filename = time.strftime( filename, time.localtime( time.time() ) )
118 timestamp = time.ctime(time.time()) 115 timestamp = time.ctime(time.time())
119 header = '[%s] : ' % ( timestamp ); 116 header = '[%s] : ' % ( timestamp );
120 if settings.get_setting('TimeStampGameLog') != '1': header = '' 117 if settings.get_setting('TimeStampGameLog') != '1': header = ''
121 try: 118 try:
122 f = open( dir_struct["user"] + filename, 'a' ) 119 f = open( dir_struct["user"] + filename, 'a' )
123 f.write( '<div class="'+c+'">%s%s</div>\n' % ( header, text ) ) 120 f.write( '<div class="'+c+'">%s%s</div>\n' % ( header, text ) )
124 f.close() 121 f.close()
125 except: 122 except Exception, e:
126 print "could not open " + dir_struct["user"] + filename + ", ignoring..." 123 print "could not open " + dir_struct["user"] + filename + ", ignoring..."
124 print 'Error given', e
127 pass 125 pass
128 126
129 # This class displayes the chat information in html? 127 # This class displayes the chat information in html?
130 # 128 #
131 # Defines: 129 # Defines:
134 # CalculateAllFonts(self, defaultsize) 132 # CalculateAllFonts(self, defaultsize)
135 # SetDefaultFontAndSize(self, fontname) 133 # SetDefaultFontAndSize(self, fontname)
136 # 134 #
137 class chat_html_window(wx.html.HtmlWindow): 135 class chat_html_window(wx.html.HtmlWindow):
138 """ a wxHTMLwindow that will load links """ 136 """ a wxHTMLwindow that will load links """
139 # initialization subroutine 137
140 #
141 # !self : instance of self
142 # !parent :
143 # !id :
144
145 def __init__(self, parent, id): 138 def __init__(self, parent, id):
146 wx.html.HtmlWindow.__init__(self, parent, id, 139 wx.html.HtmlWindow.__init__(self, parent, id,
147 style=wx.SUNKEN_BORDER|wx.html.HW_SCROLLBAR_AUTO|wx.NO_FULL_REPAINT_ON_RESIZE) 140 style=wx.SUNKEN_BORDER|wx.html.HW_SCROLLBAR_AUTO|wx.NO_FULL_REPAINT_ON_RESIZE)
148 self.parent = parent 141 self.parent = parent
149 self.build_menu() 142 self.build_menu()
150 self.Bind(wx.EVT_LEFT_UP, self.LeftUp) 143 self.Bind(wx.EVT_LEFT_UP, self.LeftUp)
151 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup) 144 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
152 if "gtk2" in wx.PlatformInfo: self.SetStandardFonts() 145 if "gtk2" in wx.PlatformInfo: self.SetStandardFonts()
153 # def __init__ - end 146
154
155
156 def onPopup(self, evt): 147 def onPopup(self, evt):
157 self.PopupMenu(self.menu) 148 self.PopupMenu(self.menu)
158 149
159
160 def LeftUp(self, event): 150 def LeftUp(self, event):
161 event.Skip() 151 event.Skip()
162 wx.CallAfter(self.parent.set_chat_text_focus, None) 152 wx.CallAfter(self.parent.set_chat_text_focus, None)
163 153
164
165 def build_menu(self): 154 def build_menu(self):
166 self.menu = wx.Menu() 155 self.menu = wx.Menu()
167 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy") 156 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy")
168 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item) 157 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item)
169 self.menu.AppendItem(item) 158 self.menu.AppendItem(item)
172 wx.TheClipboard.UsePrimarySelection(False) 161 wx.TheClipboard.UsePrimarySelection(False)
173 wx.TheClipboard.Open() 162 wx.TheClipboard.Open()
174 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText())) 163 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText()))
175 wx.TheClipboard.Close() 164 wx.TheClipboard.Close()
176 165
177
178 def scroll_down(self): 166 def scroll_down(self):
179 maxrange = self.GetScrollRange(wx.VERTICAL) 167 maxrange = self.GetScrollRange(wx.VERTICAL)
180 pagesize = self.GetScrollPageSize(wx.VERTICAL) 168 pagesize = self.GetScrollPageSize(wx.VERTICAL)
181 self.Scroll(-1, maxrange-pagesize) 169 self.Scroll(-1, maxrange-pagesize)
182 170
183
184 def mouse_wheel(self, event): 171 def mouse_wheel(self, event):
185 amt = event.GetWheelRotation() 172 amt = event.GetWheelRotation()
186 units = amt/(-(event.GetWheelDelta())) 173 units = amt/(-(event.GetWheelDelta()))
187 self.ScrollLines(units*3) 174 self.ScrollLines(units*3)
188 175
195 return self.GetPageSource().replace(self.Header(), '') 182 return self.GetPageSource().replace(self.Header(), '')
196 183
197 184
198 def GetPageSource(self): 185 def GetPageSource(self):
199 return self.GetParser().GetSource() 186 return self.GetParser().GetSource()
200
201 # This subroutine fires up the webbrowser when a link is clicked.
202 #
203 # !self : instance of self
204 # !linkinfo : instance of a class that contains the link information
205 187
206 def OnLinkClicked(self, linkinfo): 188 def OnLinkClicked(self, linkinfo):
207 href = linkinfo.GetHref() 189 href = linkinfo.GetHref()
208 wb = webbrowser.get() 190 wb = webbrowser.get()
209 wb.open(href) 191 wb.open(href)
210 # def OnLinkClicked - end 192
211
212
213 def CalculateAllFonts(self, defaultsize): 193 def CalculateAllFonts(self, defaultsize):
214 return [int(defaultsize * 0.4), 194 return [int(defaultsize * 0.4),
215 int(defaultsize * 0.7), 195 int(defaultsize * 0.7),
216 int(defaultsize), 196 int(defaultsize),
217 int(defaultsize * 1.3), 197 int(defaultsize * 1.3),
218 int(defaultsize * 1.7), 198 int(defaultsize * 1.7),
219 int(defaultsize * 2), 199 int(defaultsize * 2),
220 int(defaultsize * 2.5)] 200 int(defaultsize * 2.5)]
221 201
222
223 def SetDefaultFontAndSize(self, fontname, fontsize): 202 def SetDefaultFontAndSize(self, fontname, fontsize):
224 """Set 'fontname' to the default chat font. 203 """Set 'fontname' to the default chat font.
225 Returns current font settings in a (fontname, fontsize) tuple.""" 204 Returns current font settings in a (fontname, fontsize) tuple."""
226 self.SetFonts(fontname, "", self.CalculateAllFonts(int(fontsize))) 205 self.SetFonts(fontname, "", self.CalculateAllFonts(int(fontsize)))
227 return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize()) 206 return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize())
237 self.build_menu() 216 self.build_menu()
238 self.Bind(wx.EVT_LEFT_UP, self.LeftUp) 217 self.Bind(wx.EVT_LEFT_UP, self.LeftUp)
239 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup) 218 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup)
240 self.Bind(wx.webview.EVT_WEBVIEW_BEFORE_LOAD, self.OnLinkClicked) 219 self.Bind(wx.webview.EVT_WEBVIEW_BEFORE_LOAD, self.OnLinkClicked)
241 220
242 #Wrapers so I dont have to add special Code
243 def SetPage(self, htmlstring): 221 def SetPage(self, htmlstring):
244 self.SetPageSource(htmlstring) 222 self.SetPageSource(htmlstring)
245 223
246 def AppendToPage(self, htmlstring): 224 def AppendToPage(self, htmlstring):
247 self.SetPageSource(self.GetPageSource() + htmlstring) 225 self.SetPageSource(self.GetPageSource() + htmlstring)
364 self.create_gm_tab() 342 self.create_gm_tab()
365 self.SetSelection(0) 343 self.SetSelection(0)
366 344
367 def get_tab_index(self, chatpanel): 345 def get_tab_index(self, chatpanel):
368 "Return the index of a chatpanel in the wxNotebook." 346 "Return the index of a chatpanel in the wxNotebook."
369
370 for i in xrange(self.GetPageCount()): 347 for i in xrange(self.GetPageCount()):
371 if (self.GetPage(i) == chatpanel): 348 if (self.GetPage(i) == chatpanel):
372 return i 349 return i
373 350
374 def create_gm_tab(self): 351 def create_gm_tab(self):
448 def onPageChanged(self, event): 425 def onPageChanged(self, event):
449 """When private chattabs are selected, set the bitmap back to 'normal'.""" 426 """When private chattabs are selected, set the bitmap back to 'normal'."""
450 selected_idx = event.GetSelection() 427 selected_idx = event.GetSelection()
451 self.SetPageImage(selected_idx, 1) 428 self.SetPageImage(selected_idx, 1)
452 page = self.GetPage(selected_idx) 429 page = self.GetPage(selected_idx)
453 #wx.CallAfter(page.set_chat_text_focus, 0)
454 event.Skip() 430 event.Skip()
455 431
456 """ 432 """
457 This class defines and builds the Chat Frame for OpenRPG 433 This class defines and builds the Chat Frame for OpenRPG
458 434
503 self.activeplugins = component.get('plugins') 479 self.activeplugins = component.get('plugins')
504 self.parent = parent 480 self.parent = parent
505 # who receives outbound messages, either "all" or "playerid" string 481 # who receives outbound messages, either "all" or "playerid" string
506 self.sendtarget = sendtarget 482 self.sendtarget = sendtarget
507 self.type = tab_type 483 self.type = tab_type
508 #self.sound_player = component.get('sound') #Removing!
509 # create die roller manager
510 #self.DiceManager = component.get('DiceManager') #Removing!
511 # create rpghex tool
512 self.r_h = orpg.tools.rgbhex.RGBHex() 484 self.r_h = orpg.tools.rgbhex.RGBHex()
513 self.h = 0 485 self.h = 0
514 self.set_colors() 486 self.set_colors()
515 self.version = VERSION 487 self.version = VERSION
516 self.histidx = -1 488 self.histidx = -1
534 self.defaultFilterName = 'No Filter' 506 self.defaultFilterName = 'No Filter'
535 self.advancedFilter = False 507 self.advancedFilter = False
536 self.lastSend = 0 # this is used to help implement the player typing indicator 508 self.lastSend = 0 # this is used to help implement the player typing indicator
537 self.lastPress = 0 # this is used to help implement the player typing indicator 509 self.lastPress = 0 # this is used to help implement the player typing indicator
538 self.Bind(wx.EVT_SIZE, self.OnSize) 510 self.Bind(wx.EVT_SIZE, self.OnSize)
539 self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) #require to keep text at bottom of chat when text entry expands --SD 511 self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize)
540 self.build_ctrls() 512 self.build_ctrls()
541 StartupFont = self.settings.get_setting("defaultfont") 513 StartupFont = self.settings.get_setting("defaultfont")
542 StartupFontSize = self.settings.get_setting("defaultfontsize") 514 StartupFontSize = self.settings.get_setting("defaultfontsize")
543 if(StartupFont != "") and (StartupFontSize != ""): 515 if(StartupFont != "") and (StartupFontSize != ""):
544 try: self.set_default_font(StartupFont, int(StartupFontSize)) 516 try: self.set_default_font(StartupFont, int(StartupFontSize))
776 def get_hot_keys(self): 748 def get_hot_keys(self):
777 # dummy menus for hotkeys 749 # dummy menus for hotkeys
778 self.build_menu() 750 self.build_menu()
779 entries = [] 751 entries = []
780 entries.append((wx.ACCEL_CTRL, ord('H'), self.setChatFocusMenu.GetId())) 752 entries.append((wx.ACCEL_CTRL, ord('H'), self.setChatFocusMenu.GetId()))
781 #entries.append((wx.ACCEL_CTRL, wx.WXK_TAB, SWAP_TABS))
782 return entries 753 return entries
783 754
784 755
785 def forward_tabs(self, evt): 756 def forward_tabs(self, evt):
786 self.parent.AdvanceSelection() 757 self.parent.AdvanceSelection()
787 758
788 def back_tabs(self, evt): 759 def back_tabs(self, evt):
789 self.parent.AdvanceSelection(False) 760 self.parent.AdvanceSelection(False)
790 761
791 # This subroutine builds the controls for the chat frame
792 #
793 # !self : instance of self
794
795 def build_ctrls(self): 762 def build_ctrls(self):
796 self.chatwnd = chat_html_window(self,-1) 763 self.chatwnd = chat_html_window(self,-1)
797 self.set_colors() 764 self.set_colors()
798 wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header()) 765 wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header())
766 welcome = "<b>Welcome to <a href='http://www.knowledgearcana.com//content/view/199/128/'>"
767 welcome += DISTRO +'</a> '+ DIS_VER +' {'+BUILD+'},'
768 welcome += ' built on OpenRPG '+ VERSION +'</b>'
799 if (self.sendtarget == "all"): 769 if (self.sendtarget == "all"):
800 wx.CallAfter(self.Post, self.colorize(self.syscolor, 770 wx.CallAfter(self.Post, self.colorize(self.syscolor, welcome))
801 "<b>Welcome to <a href='http://www.openrpg.com'>OpenRPG</a> version " + self.version + "... </b>"))
802 #self.chat_cmds.on_help()
803 self.chattxt = orpg.tools.predTextCtrl.predTextCtrl(self, -1, "", 771 self.chattxt = orpg.tools.predTextCtrl.predTextCtrl(self, -1, "",
804 style=wx.TE_PROCESS_ENTER |wx.TE_PROCESS_TAB|wx.TE_LINEWRAP, 772 style=wx.TE_PROCESS_ENTER |wx.TE_PROCESS_TAB|wx.TE_LINEWRAP,
805 keyHook = self.myKeyHook, validator=None ) 773 keyHook = self.myKeyHook, validator=None )
806 self.build_bar() 774 self.build_bar()
807 self.basesizer = wx.BoxSizer(wx.VERTICAL) 775 self.basesizer = wx.BoxSizer(wx.VERTICAL)
836 self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock) 804 self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock)
837 self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel) 805 self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel)
838 self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar) 806 self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar)
839 self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down) 807 self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down)
840 self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy) 808 self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy)
841 # def build_ctrls - end
842 809
843 def build_bar(self): 810 def build_bar(self):
844 self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) 811 self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
845 self.scroll_lock = None 812 self.scroll_lock = None
846 self.numDieText = None 813 self.numDieText = None
853 self.toolbar_sizer.Add(self.textpop_lock, 0, wx.EXPAND) 820 self.toolbar_sizer.Add(self.textpop_lock, 0, wx.EXPAND)
854 self.toolbar_sizer.Add(self.scroll_lock, 0, wx.EXPAND) 821 self.toolbar_sizer.Add(self.scroll_lock, 0, wx.EXPAND)
855 self.build_formating() 822 self.build_formating()
856 self.build_colorbutton() 823 self.build_colorbutton()
857 824
858
859 def build_scroll(self): 825 def build_scroll(self):
860 self.scroll_lock = wx.Button( self, wx.ID_ANY, "Scroll ON",size= wx.Size(80,25)) 826 self.scroll_lock = wx.Button( self, wx.ID_ANY, "Scroll ON",size= wx.Size(80,25))
861 827
862
863 def build_alias(self): 828 def build_alias(self):
864 self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL) 829 self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
865 self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName]) 830 self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName])
866 self.aliasButton = createMaskedButton( self, dir_struct["icon"] + 'player.gif', 831 self.aliasButton = createMaskedButton( self, dir_struct["icon"] + 'player.gif',
867 'Refresh list of aliases from Game Tree', 832 'Refresh list of aliases from Game Tree',
947 def toggle_formating(self, act): 912 def toggle_formating(self, act):
948 if act == '0': self.toolbar_sizer.Show(self.formatSizer, False) 913 if act == '0': self.toolbar_sizer.Show(self.formatSizer, False)
949 else: self.toolbar_sizer.Show(self.formatSizer, True) 914 else: self.toolbar_sizer.Show(self.formatSizer, True)
950 self.toolbar_sizer.Layout() 915 self.toolbar_sizer.Layout()
951 916
952 # Heroman - Ideally, we would use static labels...
953
954 def build_colorbutton(self): 917 def build_colorbutton(self):
955 self.color_button = createMaskedButton(self, dir_struct["icon"]+'textcolor.gif', 918 self.color_button = createMaskedButton(self, dir_struct["icon"]+'textcolor.gif',
956 'Text Color', wx.ID_ANY, '#bdbdbd', 919 'Text Color', wx.ID_ANY, '#bdbdbd',
957 wx.BITMAP_TYPE_GIF) 920 wx.BITMAP_TYPE_GIF)
958 921
981 self.session.set_status_url(link) 944 self.session.set_status_url(link)
982 except: pass 945 except: pass
983 else: logger.general("Error, self.chatwnd.GetInternalRepresentation() return None") 946 else: logger.general("Error, self.chatwnd.GetInternalRepresentation() return None")
984 evt.Skip() 947 evt.Skip()
985 948
986 # This subroutine is registered with predTextCtrl to be run for every OnChar event
987 # It checks if we need to send a typing message
988
989 #
990 # self: duh
991 # event: raw KeyEvent from OnChar()
992
993 def myKeyHook(self, event): 949 def myKeyHook(self, event):
994 if self.session.get_status() == MPLAY_CONNECTED: # only do if we're connected 950 if self.session.get_status() == MPLAY_CONNECTED: # only do if we're connected
995 thisPress = time.time() # thisPress is local temp variable 951 thisPress = time.time() # thisPress is local temp variable
996 if (thisPress - self.lastSend) > 4: # Check to see if it's been 5 seconds since our last notice 952 if (thisPress - self.lastSend) > 4: # Check to see if it's been 5 seconds since our last notice
997 # If we're not already typing, then self.lastSend will be 0 953 # If we're not already typing, then self.lastSend will be 0
1003 return 1 959 return 1
1004 else: 960 else:
1005 logger.debug("Exit chat_panel->myKeyHook(self, event) return 0") 961 logger.debug("Exit chat_panel->myKeyHook(self, event) return 0")
1006 return 0 962 return 0
1007 963
1008 # This subroutine gets called once a second by the typing Timer
1009 # It checks if we need to send a not_typing message
1010 #
1011 # self: duh
1012
1013 def typingTimerFunc(self, event): 964 def typingTimerFunc(self, event):
1014 #following added by mDuo13 965 #following added by mDuo13
1015 ##############refresh_counter()############## 966 ##############refresh_counter()##############
1016 for plugin_fname in self.activeplugins.keys(): 967 for plugin_fname in self.activeplugins.keys():
1017 plugin = self.activeplugins[plugin_fname] 968 plugin = self.activeplugins[plugin_fname]
1025 thisTime = time.time() # thisTime is a local temp variable 976 thisTime = time.time() # thisTime is a local temp variable
1026 if (thisTime - self.lastPress) > 4: # Check to see if it's been 5 seconds since our last keystroke 977 if (thisTime - self.lastPress) > 4: # Check to see if it's been 5 seconds since our last keystroke
1027 # If we're not already typing, then self.lastSend will be 0 978 # If we're not already typing, then self.lastSend will be 0
1028 979
1029 self.sendTyping(0) # send a typing event here (0 for False) 980 self.sendTyping(0) # send a typing event here (0 for False)
1030 # This subroutine actually takes care of sending the messages for typing/not_typing events 981
1031 #
1032 # self: duh
1033 # typing: boolean
1034
1035
1036 def sendTyping(self, typing): 982 def sendTyping(self, typing):
1037 if typing: 983 if typing:
1038 self.lastSend = time.time() # remember our send time for use in myKeyHook() 984 self.lastSend = time.time() # remember our send time for use in myKeyHook()
1039 #I think this is cleaner 985 #I think this is cleaner
1040 status_text = self.settings.get_setting('TypingStatusAlias') 986 status_text = self.settings.get_setting('TypingStatusAlias')
1045 #I think this is cleaner 991 #I think this is cleaner
1046 status_text = self.settings.get_setting('IdleStatusAlias') 992 status_text = self.settings.get_setting('IdleStatusAlias')
1047 if status_text == "" or status_text == None: status_text = "Idle" 993 if status_text == "" or status_text == None: status_text = "Idle"
1048 self.session.set_text_status(status_text) 994 self.session.set_text_status(status_text)
1049 995
1050 # This subroutine sets the colors of the chat based on the settings in the
1051 # self instance.
1052 #
1053 # !self : instance of self
1054
1055 def set_colors(self): 996 def set_colors(self):
1056 # chat window backround color 997 # chat window backround color
1057 self.bgcolor = self.settings.get_setting('bgcolor') 998 self.bgcolor = self.settings.get_setting('bgcolor')
1058 # chat window normal text color 999 # chat window normal text color
1059 self.textcolor = self.settings.get_setting('textcolor') 1000 self.textcolor = self.settings.get_setting('textcolor')
1065 self.infocolor = self.settings.get_setting('infocolor') 1006 self.infocolor = self.settings.get_setting('infocolor')
1066 # color of emotes 1007 # color of emotes
1067 self.emotecolor = self.settings.get_setting('emotecolor') 1008 self.emotecolor = self.settings.get_setting('emotecolor')
1068 # color of whispers 1009 # color of whispers
1069 self.whispercolor = self.settings.get_setting('whispercolor') 1010 self.whispercolor = self.settings.get_setting('whispercolor')
1070 # def set_colors - end
1071
1072 # This subroutine will insert text into the chat window
1073 #
1074 # !self : instance of self
1075 # !txt : text to be inserted into the chat window
1076 1011
1077 def set_chat_text(self, txt): 1012 def set_chat_text(self, txt):
1078 self.chattxt.SetValue(txt) 1013 self.chattxt.SetValue(txt)
1079 self.chattxt.SetFocus() 1014 self.chattxt.SetFocus()
1080 self.chattxt.SetInsertionPointEnd() 1015 self.chattxt.SetInsertionPointEnd()
1081 # def set_chat_text - end
1082 1016
1083 1017
1084 def get_chat_text(self): 1018 def get_chat_text(self):
1085 return self.chattxt.GetValue() 1019 return self.chattxt.GetValue()
1086 1020
1087 # This subroutine sets the focus to the chat window 1021 # This subroutine sets the focus to the chat window
1088 1022
1089 def set_chat_text_focus(self, event): 1023 def set_chat_text_focus(self, event):
1090 wx.CallAfter(self.chattxt.SetFocus) 1024 wx.CallAfter(self.chattxt.SetFocus)
1091 # def set_chat_text_focus - end
1092
1093 # This subrtouine grabs the user input and make the special keys and
1094 # modifiers work.
1095 #
1096 # !self : instance of self
1097 # !event :
1098 #
1099 # Note: self.chattxt now handles it's own Key events. It does, however still
1100 # call it's parent's (self) OnChar to handle "default" behavior.
1101 1025
1102 def submit_chat_text(self, s): 1026 def submit_chat_text(self, s):
1103 self.histidx = -1 1027 self.histidx = -1
1104 self.temptext = "" 1028 self.temptext = ""
1105 self.history = [s] + self.history 1029 self.history = [s] + self.history
1106 #if not len(macroText): self.chattxt.SetValue("")
1107 1030
1108 # play sound 1031 # play sound
1109 sound_file = self.settings.get_setting("SendSound") 1032 sound_file = self.settings.get_setting("SendSound")
1110 if sound_file != '': component.get('sound').play(sound_file) 1033 if sound_file != '': component.get('sound').play(sound_file)
1111 if s[0] != "/": ## it's not a slash command 1034 if s[0] != "/": ## it's not a slash command
1142 1065
1143 ## UP KEY 1066 ## UP KEY
1144 elif event.GetKeyCode() == wx.WXK_UP: 1067 elif event.GetKeyCode() == wx.WXK_UP:
1145 logger.debug("event.GetKeyCode() == wx.WXK_UP") 1068 logger.debug("event.GetKeyCode() == wx.WXK_UP")
1146 if self.histidx < len(self.history)-1: 1069 if self.histidx < len(self.history)-1:
1147 #text that's not in history but also hasn't been sent to chat gets stored in self.temptext
1148 #this way if someone presses the up key, they don't lose their current message permanently
1149 #(unless they also press enter at the time)
1150 if self.histidx is -1: self.temptext = self.chattxt.GetValue() 1070 if self.histidx is -1: self.temptext = self.chattxt.GetValue()
1151 self.histidx += 1 1071 self.histidx += 1
1152 self.chattxt.SetValue(self.history[self.histidx]) 1072 self.chattxt.SetValue(self.history[self.histidx])
1153 self.chattxt.SetInsertionPointEnd() 1073 self.chattxt.SetInsertionPointEnd()
1154 else: 1074 else:
1155 self.histidx = len(self.history) -1#in case it got too high somehow, this should fix it 1075 self.histidx = len(self.history) -1
1156 #self.InfoPost("**Going up? I don't think so.**")
1157 #print self.histidx, "in",self.history
1158 1076
1159 ## DOWN KEY 1077 ## DOWN KEY
1160 elif event.GetKeyCode() == wx.WXK_DOWN: 1078 elif event.GetKeyCode() == wx.WXK_DOWN:
1161 logger.debug("event.GetKeyCode() == wx.WXK_DOWN") 1079 logger.debug("event.GetKeyCode() == wx.WXK_DOWN")
1162 #histidx of -1 indicates currently viewing text that's not in self.history 1080 #histidx of -1 indicates currently viewing text that's not in self.history
1164 self.histidx -= 1 1082 self.histidx -= 1
1165 if self.histidx is -1: #remember, it just decreased 1083 if self.histidx is -1: #remember, it just decreased
1166 self.chattxt.SetValue(self.temptext) 1084 self.chattxt.SetValue(self.temptext)
1167 else: self.chattxt.SetValue(self.history[self.histidx]) 1085 else: self.chattxt.SetValue(self.history[self.histidx])
1168 self.chattxt.SetInsertionPointEnd() 1086 self.chattxt.SetInsertionPointEnd()
1169 else: self.histidx = -1 #just in case it somehow got below -1, this should fix it 1087 else: self.histidx = -1
1170 #self.InfoPost("**Going down? I don't think so.**")
1171 #print self.histidx, "in",self.history
1172 1088
1173 ## TAB KEY 1089 ## TAB KEY
1174 elif event.GetKeyCode() == wx.WXK_TAB: 1090 elif event.GetKeyCode() == wx.WXK_TAB:
1175 logger.debug("event.GetKeyCode() == wx.WXK_TAB") 1091 logger.debug("event.GetKeyCode() == wx.WXK_TAB")
1176 if s !="": 1092 if s !="":
1240 return 1156 return
1241 1157
1242 ## NOTHING 1158 ## NOTHING
1243 else: event.Skip() 1159 else: event.Skip()
1244 logger.debug("Exit chat_panel->OnChar(self, event)") 1160 logger.debug("Exit chat_panel->OnChar(self, event)")
1245 # def OnChar - end
1246
1247 1161
1248 def onDieRoll(self, evt): 1162 def onDieRoll(self, evt):
1249 """Roll the dice based on the button pressed and the die modifiers entered, if any.""" 1163 """Roll the dice based on the button pressed and the die modifiers entered, if any."""
1250 # Get any die modifiers if they have been entered 1164 # Get any die modifiers if they have been entered
1251 numDie = self.numDieText.GetValue() 1165 numDie = self.numDieText.GetValue()
1258 dieText += dieMod 1172 dieText += dieMod
1259 dieText = "[" + dieText + "]" 1173 dieText = "[" + dieText + "]"
1260 self.ParsePost(dieText, 1, 1) 1174 self.ParsePost(dieText, 1, 1)
1261 self.chattxt.SetFocus() 1175 self.chattxt.SetFocus()
1262 1176
1263 # This subroutine saves a chat buffer as html to a file chosen via a
1264 # FileDialog.
1265 #
1266 # !self : instance of self
1267 # !evt :
1268
1269 def on_chat_save(self, evt): 1177 def on_chat_save(self, evt):
1270 f = wx.FileDialog(self,"Save Chat Buffer",".","","HTM* (*.htm*)|*.htm*|HTML (*.html)|*.html|HTM (*.htm)|*.htm",wx.SAVE) 1178 f = wx.FileDialog(self,"Save Chat Buffer",".","","HTM* (*.htm*)|*.htm*|HTML (*.html)|*.html|HTM (*.htm)|*.htm",wx.SAVE)
1271 if f.ShowModal() == wx.ID_OK: 1179 if f.ShowModal() == wx.ID_OK:
1272 file = open(f.GetPath(), "w") 1180 file = open(f.GetPath(), "w")
1273 file.write(self.ResetPage() + "</body></html>") 1181 file.write(self.ResetPage() + "</body></html>")
1274 file.close() 1182 file.close()
1275 f.Destroy() 1183 f.Destroy()
1276 os.chdir(dir_struct["home"]) 1184 os.chdir(dir_struct["home"])
1277 # def on_chat_save - end 1185
1278
1279
1280 def ResetPage(self): 1186 def ResetPage(self):
1281 self.set_colors() 1187 self.set_colors()
1282 buffertext = self.chatwnd.Header() + "\n" 1188 buffertext = self.chatwnd.Header() + "\n"
1283 buffertext += chat_util.strip_body_tags(self.chatwnd.StripHeader()).replace("<br>", 1189 buffertext += chat_util.strip_body_tags(self.chatwnd.StripHeader()).replace("<br>",
1284 "<br />").replace('</html>', 1190 "<br />").replace('</html>',
1285 '').replace("<br />", 1191 '').replace("<br />",
1286 "<br />\n").replace("\n\n", '') 1192 "<br />\n").replace("\n\n", '')
1287 return buffertext 1193 return buffertext
1288 1194
1289 # This subroutine sets the color of selected text, or base text color if
1290 # nothing is selected
1291
1292 def on_text_color(self, event): 1195 def on_text_color(self, event):
1293 hexcolor = self.r_h.do_hex_color_dlg(self) 1196 hexcolor = self.r_h.do_hex_color_dlg(self)
1294 if hexcolor != None: 1197 if hexcolor != None:
1295 (beg,end) = self.chattxt.GetSelection() 1198 (beg,end) = self.chattxt.GetSelection()
1296 if beg != end: 1199 if beg != end:
1303 self.color_button.SetBackgroundColour(hexcolor) 1206 self.color_button.SetBackgroundColour(hexcolor)
1304 self.mytextcolor = hexcolor 1207 self.mytextcolor = hexcolor
1305 self.settings.set_setting('mytextcolor',hexcolor) 1208 self.settings.set_setting('mytextcolor',hexcolor)
1306 self.set_colors() 1209 self.set_colors()
1307 self.Post() 1210 self.Post()
1308 # def on_text_color - end 1211
1309
1310 # This subroutine take a color and a text string and formats it into html.
1311 #
1312 # !self : instance of self
1313 # !color : color for the text to be set
1314 # !text : text string to be included in the html.
1315
1316 def colorize(self, color, text): 1212 def colorize(self, color, text):
1317 """Puts font tags of 'color' around 'text' value, and returns the string""" 1213 """Puts font tags of 'color' around 'text' value, and returns the string"""
1318 return "<font color='" + color + "'>" + text + "</font>" 1214 return "<font color='" + color + "'>" + text + "</font>"
1319 # def colorize - end 1215
1320
1321 # This subroutine takes and event and inserts text with the basic format
1322 # tags included.
1323 #
1324 # !self : instance of self
1325 # !event :
1326
1327 def on_text_format(self, event): 1216 def on_text_format(self, event):
1328 id = event.GetId() 1217 id = event.GetId()
1329 txt = self.chattxt.GetValue() 1218 txt = self.chattxt.GetValue()
1330 (beg,end) = self.chattxt.GetSelection() 1219 (beg,end) = self.chattxt.GetSelection()
1331 if beg != end: sel_txt = txt[beg:end] 1220 if beg != end: sel_txt = txt[beg:end]
1336 if beg != end: txt = txt[:beg] + sel_txt + txt[end:] 1225 if beg != end: txt = txt[:beg] + sel_txt + txt[end:]
1337 else: txt = sel_txt 1226 else: txt = sel_txt
1338 self.chattxt.SetValue(txt) 1227 self.chattxt.SetValue(txt)
1339 self.chattxt.SetInsertionPointEnd() 1228 self.chattxt.SetInsertionPointEnd()
1340 self.chattxt.SetFocus() 1229 self.chattxt.SetFocus()
1341 # def on_text_format - end 1230
1342
1343
1344 def lock_scroll(self, event): 1231 def lock_scroll(self, event):
1345 if self.lockscroll: 1232 if self.lockscroll:
1346 self.lockscroll = False 1233 self.lockscroll = False
1347 self.scroll_lock.SetLabel("Scroll ON") 1234 self.scroll_lock.SetLabel("Scroll ON")
1348 if len(self.storedata) != 0: 1235 if len(self.storedata) != 0:
1351 self.scroll_down() 1238 self.scroll_down()
1352 else: 1239 else:
1353 self.lockscroll = True 1240 self.lockscroll = True
1354 self.scroll_lock.SetLabel("Scroll OFF") 1241 self.scroll_lock.SetLabel("Scroll OFF")
1355 1242
1356 # This subroutine will popup a text window with the chatbuffer contents
1357 #
1358 # !self : instance of self
1359 # !event :
1360
1361 def pop_textpop(self, event): 1243 def pop_textpop(self, event):
1362 """searchable popup text view of chatbuffer""" 1244 """searchable popup text view of chatbuffer"""
1363 h_buffertext = self.ResetPage() 1245 h_buffertext = self.ResetPage()
1364 h_dlg = orpgScrolledMessageFrameEditor(self, h_buffertext, "Text View of Chat Window", None, (500,300)) 1246 h_dlg = orpgScrolledMessageFrameEditor(self, h_buffertext, "Text View of Chat Window", None, (500,300))
1365 h_dlg.Show(True) 1247 h_dlg.Show(True)
1366 1248
1367 # This subroutine will change the dimension of the window
1368 #
1369 # !self : instance of self
1370 # !event :
1371
1372 def OnSize(self, event=None): 1249 def OnSize(self, event=None):
1373 event.Skip() 1250 event.Skip()
1374 wx.CallAfter(self.scroll_down) 1251 wx.CallAfter(self.scroll_down)
1375 # def OnSize - end 1252
1376
1377
1378 def scroll_down(self): 1253 def scroll_down(self):
1379 self.Freeze() 1254 self.Freeze()
1380 self.chatwnd.scroll_down() 1255 self.chatwnd.scroll_down()
1381 self.Thaw() 1256 self.Thaw()
1382 1257
1384 1259
1385 def PurgeChat(self): 1260 def PurgeChat(self):
1386 self.set_colors() 1261 self.set_colors()
1387 self.chatwnd.SetPage(self.chatwnd.Header()) 1262 self.chatwnd.SetPage(self.chatwnd.Header())
1388 1263
1389
1390 def system_message(self, text): 1264 def system_message(self, text):
1391 self.send_chat_message(text,chat_msg.SYSTEM_MESSAGE) 1265 self.send_chat_message(text,chat_msg.SYSTEM_MESSAGE)
1392 self.SystemPost(text) 1266 self.SystemPost(text)
1393 1267
1394
1395 def info_message(self, text): 1268 def info_message(self, text):
1396 self.send_chat_message(text,chat_msg.INFO_MESSAGE) 1269 self.send_chat_message(text,chat_msg.INFO_MESSAGE)
1397 self.InfoPost(text) 1270 self.InfoPost(text)
1398 1271
1399
1400 def get_gms(self): 1272 def get_gms(self):
1401 the_gms = [] 1273 the_gms = []
1402 for playerid in self.session.players: 1274 for playerid in self.session.players:
1403 if len(self.session.players[playerid])>7: 1275 if len(self.session.players[playerid])>7:
1404 if self.session.players[playerid][7]=="GM" and self.session.group_id != '0': the_gms += [playerid] 1276 if self.session.players[playerid][7]=="GM" and self.session.group_id != '0': the_gms += [playerid]
1405 return the_gms 1277 return the_gms
1406 1278
1407
1408 def GetName(self): 1279 def GetName(self):
1409 self.AliasLib = component.get('alias') 1280 self.AliasLib = component.get('alias')
1410 player = self.session.get_my_info() 1281 player = self.session.get_my_info()
1411 if self.AliasLib != None: 1282 if self.AliasLib != None:
1412 self.AliasLib.alias = self.aliasList.GetStringSelection(); 1283 self.AliasLib.alias = self.aliasList.GetStringSelection();
1413 if self.AliasLib.alias[0] != self.defaultAliasName: 1284 if self.AliasLib.alias[0] != self.defaultAliasName:
1414 logger.debug("Exit chat_panel->GetName(self)") 1285 logger.debug("Exit chat_panel->GetName(self)")
1415 return [self.chat_display_name([self.AliasLib.alias[0], player[1], player[2]]), self.AliasLib.alias[1]] 1286 return [self.chat_display_name([self.AliasLib.alias[0], player[1], player[2]]), self.AliasLib.alias[1]]
1416 return [self.chat_display_name(player), "Default"] 1287 return [self.chat_display_name(player), "Default"]
1417 1288
1418
1419 def GetFilteredText(self, text): 1289 def GetFilteredText(self, text):
1420 advregex = re.compile('\"(.*?)\"', re.I) 1290 advregex = re.compile('\"(.*?)\"', re.I)
1421 self.AliasLib = component.get('alias') 1291 self.AliasLib = component.get('alias')
1422 if self.AliasLib != None: 1292 if self.AliasLib != None:
1423 self.AliasLib.filter = self.filterList.GetSelection()-1; 1293 self.AliasLib.filter = self.filterList.GetSelection()-1;
1428 match = m.group(0) 1298 match = m.group(0)
1429 newmatch = re.sub(rule[0], rule[1], match) 1299 newmatch = re.sub(rule[0], rule[1], match)
1430 text = text.replace(match, newmatch) 1300 text = text.replace(match, newmatch)
1431 return text 1301 return text
1432 1302
1433
1434 def emote_message(self, text): 1303 def emote_message(self, text):
1435 text = self.NormalizeParse(text) 1304 text = Parse.Normalize(text)
1436 text = self.colorize(self.emotecolor, text) 1305 text = self.colorize(self.emotecolor, text)
1437
1438 if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE) 1306 if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE)
1439 elif self.type == MAIN_TAB and self.sendtarget == "gm": 1307 elif self.type == MAIN_TAB and self.sendtarget == "gm":
1440 msg_type = chat_msg.WHISPER_EMOTE_MESSAGE 1308 msg_type = chat_msg.WHISPER_EMOTE_MESSAGE
1441 the_gms = self.get_gms() 1309 the_gms = self.get_gms()
1442 for each_gm in the_gms: self.send_chat_message(text,chat_msg.WHISPER_EMOTE_MESSAGE, str(each_gm)) 1310 for each_gm in the_gms: self.send_chat_message(text,chat_msg.WHISPER_EMOTE_MESSAGE, str(each_gm))
1447 elif self.type == NULL_TAB: pass 1315 elif self.type == NULL_TAB: pass
1448 name = self.GetName()[0] 1316 name = self.GetName()[0]
1449 text = "** " + name + " " + text + " **" 1317 text = "** " + name + " " + text + " **"
1450 self.EmotePost(text) 1318 self.EmotePost(text)
1451 1319
1452
1453 def whisper_to_players(self, text, player_ids): 1320 def whisper_to_players(self, text, player_ids):
1454 tabbed_whispers_p = self.settings.get_setting("tabbedwhispers") 1321 tabbed_whispers_p = self.settings.get_setting("tabbedwhispers")
1455 # Heroman - apply any filtering selected 1322 text = Parse.Normalize(text)
1456 text = self.NormalizeParse(text)
1457 player_names = "" 1323 player_names = ""
1458 # post to our chat before we colorize
1459 for m in player_ids: 1324 for m in player_ids:
1460 id = m.strip() 1325 id = m.strip()
1461 if self.session.is_valid_id(id): 1326 if self.session.is_valid_id(id):
1462 returned_name = self.session.get_player_by_player_id(id)[0] 1327 returned_name = self.session.get_player_by_player_id(id)[0]
1463 player_names += returned_name 1328 player_names += returned_name
1467 player_names += ", " 1332 player_names += ", "
1468 comma = "," 1333 comma = ","
1469 comma.join(player_ids) 1334 comma.join(player_ids)
1470 if (self.sendtarget == "all"): 1335 if (self.sendtarget == "all"):
1471 self.InfoPost("<i>whispering to "+ player_names + " " + text + "</i> ") 1336 self.InfoPost("<i>whispering to "+ player_names + " " + text + "</i> ")
1472 # colorize and loop, sending whisper messages to all valid clients
1473 text = self.colorize(self.mytextcolor, text) 1337 text = self.colorize(self.mytextcolor, text)
1474 for id in player_ids: 1338 for id in player_ids:
1475 id = id.strip() 1339 id = id.strip()
1476 if self.session.is_valid_id(id): self.send_chat_message(text,chat_msg.WHISPER_MESSAGE,id) 1340 if self.session.is_valid_id(id): self.send_chat_message(text,chat_msg.WHISPER_MESSAGE,id)
1477 else: self.InfoPost(id + " Unknown!") 1341 else: self.InfoPost(id + " Unknown!")
1499 if turnedoff: self.settings.set_setting("ShowIDInChat", "1") 1363 if turnedoff: self.settings.set_setting("ShowIDInChat", "1")
1500 msg.set_alias(playername) 1364 msg.set_alias(playername)
1501 if send: self.session.send(msg.toxml(),player_id) 1365 if send: self.session.send(msg.toxml(),player_id)
1502 del msg 1366 del msg
1503 1367
1504 #### incoming chat message handler #####
1505
1506 def post_incoming_msg(self, msg, player): 1368 def post_incoming_msg(self, msg, player):
1507
1508 # pull data
1509 type = msg.get_type() 1369 type = msg.get_type()
1510 text = msg.get_text() 1370 text = msg.get_text()
1511 alias = msg.get_alias() 1371 alias = msg.get_alias()
1512 # who sent us the message? 1372 # who sent us the message?
1513 if alias: display_name = self.chat_display_name([alias, player[1], player[2]]) 1373 if alias: display_name = self.chat_display_name([alias, player[1], player[2]])
1520 try: text, type, name = plugin.plugin_incoming_msg(text, type, display_name, player) 1380 try: text, type, name = plugin.plugin_incoming_msg(text, type, display_name, player)
1521 except Exception, e: 1381 except Exception, e:
1522 if str(e) != "'module' object has no attribute 'receive_msg'": 1382 if str(e) != "'module' object has no attribute 'receive_msg'":
1523 logger.general(traceback.format_exc()) 1383 logger.general(traceback.format_exc())
1524 logger.general("EXCEPTION: " + str(e)) 1384 logger.general("EXCEPTION: " + str(e))
1525 #end mDuo13 added code
1526 #image stripping for players' names
1527 strip_img = self.settings.get_setting("Show_Images_In_Chat") 1385 strip_img = self.settings.get_setting("Show_Images_In_Chat")
1528 if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name) 1386 if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name)
1529 #end image stripping. --mDuo13, July 11th, 2005
1530 # default sound
1531 recvSound = "RecvSound" 1387 recvSound = "RecvSound"
1532 # act on the type of messsage 1388 # act on the type of messsage
1533 if (type == chat_msg.CHAT_MESSAGE): 1389 if (type == chat_msg.CHAT_MESSAGE):
1534 text = "<b>" + display_name + "</b>: " + text 1390 text = "<b>" + display_name + "</b>: " + text
1535 self.Post(text) 1391 self.Post(text)
1622 self.parent.newMsg(0) 1478 self.parent.newMsg(0)
1623 # playe sound 1479 # playe sound
1624 sound_file = self.settings.get_setting(recvSound) 1480 sound_file = self.settings.get_setting(recvSound)
1625 if sound_file != '': 1481 if sound_file != '':
1626 component.get('sound').play(sound_file) 1482 component.get('sound').play(sound_file)
1483
1627 #### Posting helpers ##### 1484 #### Posting helpers #####
1628 1485
1629
1630 def InfoPost(self, s): 1486 def InfoPost(self, s):
1631 self.Post(self.colorize(self.infocolor, s), c='info') 1487 self.Post(self.colorize(self.infocolor, s), c='info')
1632 1488
1633
1634 def SystemPost(self, s): 1489 def SystemPost(self, s):
1635 self.Post(self.colorize(self.syscolor, s), c='system') 1490 self.Post(self.colorize(self.syscolor, s), c='system')
1636 1491
1637
1638 def EmotePost(self, s): 1492 def EmotePost(self, s):
1639 self.Post(self.colorize(self.emotecolor, s), c='emote') 1493 self.Post(self.colorize(self.emotecolor, s), c='emote')
1640 1494
1641 #### Standard Post method ##### 1495 #### Standard Post method #####
1642 1496
1673 s = self.colorize(self.mytextcolor, s) 1527 s = self.colorize(self.mytextcolor, s)
1674 else: name = "" 1528 else: name = ""
1675 if aliasInfo[1] != 'Default': 1529 if aliasInfo[1] != 'Default':
1676 self.settings.set_setting("mytextcolor", defaultcolor) 1530 self.settings.set_setting("mytextcolor", defaultcolor)
1677 self.set_colors() 1531 self.set_colors()
1678 #following line based on sourceforge patch #880403 from mDuo
1679 # EDIT: Had to rework blank line check to handle malformed HTML throwing error.
1680 # this limits the effectiveness of this check -SD
1681 lineHasText = 1 1532 lineHasText = 1
1682 try: lineHasText = strip_html(s).replace("&nbsp;","").replace(" ","").strip()!="" 1533 try: lineHasText = strip_html(s).replace("&nbsp;","").replace(" ","").strip()!=""
1683 except: 1534 except:
1684 # HTML parser has errored out (most likely). Being as all we are doing is
1685 # scanning for empty/blank lines anyway there is no harm in letting a
1686 # troublesome message though. Worst case is a blank line to chat.
1687 lineHasText = 1 1535 lineHasText = 1
1688 if lineHasText: 1536 if lineHasText:
1689 #following added by mDuo13 1537 #following added by mDuo13
1690 if myself: 1538 if myself:
1691 s2 = s 1539 s2 = s
1729 elif self.type == WHISPER_TAB: self.whisper_to_players(s, [self.sendtarget]) 1577 elif self.type == WHISPER_TAB: self.whisper_to_players(s, [self.sendtarget])
1730 elif self.type == NULL_TAB: pass 1578 elif self.type == NULL_TAB: pass
1731 else: self.InfoPost("Failed to send message, unknown send type for this tab") 1579 else: self.InfoPost("Failed to send message, unknown send type for this tab")
1732 self.parsed=0 1580 self.parsed=0
1733 1581
1734 #
1735 # TimeIndexString()
1736 #
1737 # time indexing for chat display only (don't log time indexing)
1738 # added by Snowdog 4/04
1739
1740 def TimeIndexString(self): 1582 def TimeIndexString(self):
1741 try: 1583 try:
1742 mtime = "" 1584 mtime = ""
1743 if self.settings.get_setting('Chat_Time_Indexing') == "0": pass 1585 if self.settings.get_setting('Chat_Time_Indexing') == "0": pass
1744 elif self.settings.get_setting('Chat_Time_Indexing') == "1": 1586 elif self.settings.get_setting('Chat_Time_Indexing') == "1":
1747 except Exception, e: 1589 except Exception, e:
1748 logger.general(traceback.format_exc()) 1590 logger.general(traceback.format_exc())
1749 logger.general("EXCEPTION: " + str(e)) 1591 logger.general("EXCEPTION: " + str(e))
1750 return "[ERROR]" 1592 return "[ERROR]"
1751 1593
1752 #### Post with parsing dice ####
1753
1754 def ParsePost(self, s, send=False, myself=False): 1594 def ParsePost(self, s, send=False, myself=False):
1755 s = self.NormalizeParse(s) 1595 s = Parse.Normalize(s)
1756 self.set_colors() 1596 self.set_colors()
1757 self.Post(s,send,myself) 1597 self.Post(s,send,myself)
1758
1759 def NormalizeParse(self, s):
1760 for plugin_fname in self.activeplugins.keys():
1761 plugin = self.activeplugins[plugin_fname]
1762 try: s = plugin.pre_parse(s)
1763 except Exception, e:
1764 if str(e) != "'module' object has no attribute 'post_msg'":
1765 logger.general(traceback.format_exc())
1766 logger.general("EXCEPTION: " + str(e))
1767 if self.parsed == 0:
1768 s = self.ParseNode(s)
1769 s = self.ParseDice(s)
1770 s = self.ParseFilter(s)
1771 self.parsed = 1
1772 return s
1773
1774 def ParseFilter(self, s):
1775 s = self.GetFilteredText(s)
1776 return s
1777
1778 def ParseNode(self, s):
1779 """Parses player input for embedded nodes rolls"""
1780 cur_loc = 0
1781 #[a-zA-Z0-9 _\-\.]
1782 reg = re.compile("(!@(.*?)@!)")
1783 matches = reg.findall(s)
1784 for i in xrange(0,len(matches)):
1785 newstr = self.ParseNode(self.resolve_nodes(matches[i][1]))
1786 s = s.replace(matches[i][0], newstr, 1)
1787 return s
1788
1789 def ParseDice(self, s):
1790 """Parses player input for embedded dice rolls"""
1791 reg = re.compile("\[([^]]*?)\]")
1792 matches = reg.findall(s)
1793 for i in xrange(0,len(matches)):
1794 newstr = self.PraseUnknowns(matches[i])
1795 qmode = 0
1796 newstr1 = newstr
1797 if newstr[0].lower() == 'q':
1798 newstr = newstr[1:]
1799 qmode = 1
1800 if newstr[0].lower() == '#':
1801 newstr = newstr[1:]
1802 qmode = 2
1803 try: newstr = component.get('DiceManager').proccessRoll(newstr)
1804 except: pass
1805 if qmode == 1:
1806 s = s.replace("[" + matches[i] + "]",
1807 "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1)
1808 elif qmode == 2:
1809 s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1)
1810 else: s = s.replace("[" + matches[i] + "]",
1811 "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1)
1812 return s
1813
1814 def PraseUnknowns(self, s):
1815 # Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY
1816 newstr = "0"
1817 reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)")
1818 matches = reg.findall(s)
1819 for i in xrange(0,len(matches)):
1820 lb = "Replace '?' with: "
1821 if len(matches[i][0]):
1822 lb = matches[i][1] + "?: "
1823 dlg = wx.TextEntryDialog(self, lb, "Missing Value?")
1824 dlg.SetValue('')
1825 if matches[i][0] != '':
1826 dlg.SetTitle("Enter Value for " + matches[i][1])
1827 if dlg.ShowModal() == wx.ID_OK: newstr = dlg.GetValue()
1828 if newstr == '': newstr = '0'
1829 s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1)
1830 dlg.Destroy()
1831 return s
1832 1598
1833 # This subroutine builds a chat display name. 1599 # This subroutine builds a chat display name.
1834 # 1600 #
1835 def chat_display_name(self, player): 1601 def chat_display_name(self, player):
1836 if self.settings.get_setting("ShowIDInChat") == "0": 1602 if self.settings.get_setting("ShowIDInChat") == "0":
1852 dlg.Destroy() 1618 dlg.Destroy()
1853 return hexcolor 1619 return hexcolor
1854 else: 1620 else:
1855 dlg.Destroy() 1621 dlg.Destroy()
1856 return None 1622 return None
1623
1857 # def get_color - end 1624 # def get_color - end
1858
1859 def replace_quotes(self, s): 1625 def replace_quotes(self, s):
1860 in_tag = 0 1626 in_tag = 0
1861 i = 0 1627 i = 0
1862 rs = s[:] 1628 rs = s[:]
1863 for c in s: 1629 for c in s:
1867 elif c == '"': 1633 elif c == '"':
1868 if in_tag: rs = rs[:i] + "'" + rs[i+1:] 1634 if in_tag: rs = rs[:i] + "'" + rs[i+1:]
1869 i += 1 1635 i += 1
1870 return rs 1636 return rs
1871 1637
1872 def resolve_loop(self, node, path, step, depth):
1873 if step == depth:
1874 return self.resolution(node)
1875 else:
1876 child_list = node.findall('nodehandler')
1877 for child in child_list:
1878 if step == depth: break
1879 if child.get('name') == path[step]:
1880 node = child
1881 step += 1
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)
1886 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth)
1887 else: self.resolve_loop(node, path, step, depth)
1888
1889 def resolve_grid(self, node, path, step, depth):
1890 if step == depth:
1891 self.data = 'Invalid Grid Reference!'
1892 return
1893 cell = tuple(path[step].strip('(').strip(')').split(','))
1894 grid = node.find('grid')
1895 rows = grid.findall('row')
1896 col = rows[int(self.ParseDice(cell[0]))-1].findall('cell')
1897 try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data'
1898 except: self.data = 'Invalid Grid Reference!'
1899 return
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
1966 def resolve_cust_loop(self, node, path, step, depth):
1967 node_class = node.get('class')
1968 ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ##
1969 if step == depth: self.resolution(node)
1970 ##Build Abilities dictionary##
1971 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities')
1972 else: ab = node.find('abilities')
1973 ab_list = ab.findall('stat'); pc_stats = {}
1974
1975 for ability in ab_list:
1976 pc_stats[ability.get('name')] = (
1977 str(ability.get('base')),
1978 str((int(ability.get('base'))-10)/2) )
1979 pc_stats[ability.get('abbr')] = (
1980 str(ability.get('base')),
1981 str((int(ability.get('base'))-10)/2) )
1982
1983 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves')
1984 else: ab = node.find('saves')
1985 ab_list = ab.findall('save')
1986 for save in ab_list:
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]) ) )
1988 if save.get('name') == 'Fortitude': abbr = 'Fort'
1989 if save.get('name') == 'Reflex': abbr = 'Ref'
1990 if save.get('name') == 'Will': abbr = 'Will'
1991 pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) )
1992
1993 if path[step].lower() == 'skill':
1994 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
1995 node = node.find('skills')
1996 child_list = node.findall('skill')
1997 for child in child_list:
1998 if path[step+1].lower() == child.get('name').lower():
1999 if step+2 == depth: self.data = child.get('rank')
2000 elif path[step+2].lower() == 'check':
2001 self.data = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']'
2002 return
2003
2004 if path[step].lower() == 'feat':
2005 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf')
2006 node = node.find('feats')
2007 child_list = node.findall('feat')
2008 for child in child_list:
2009 if path[step+1].lower() == child.get('name').lower():
2010 if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
2011 return
2012 if path[step].lower() == 'cast':
2013 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snp')
2014 node = node.find('spells')
2015 child_list = node.findall('spell')
2016 for child in child_list:
2017 if path[step+1].lower() == child.get('name').lower():
2018 if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc')
2019 return
2020 if path[step].lower() == 'attack':
2021 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat')
2022 if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm':
2023 bonus_text = '(Melee)'
2024 bonus = node.find('attacks')
2025 bonus = bonus.find('melee')
2026 bonus = bonus.attrib; d = int(pc_stats['Str'][1])
2027 elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r':
2028 bonus_text = '(Ranged)'
2029 bonus = node.find('attacks')
2030 bonus = bonus.find('ranged')
2031 bonus = bonus.attrib; d = int(pc_stats['Dex'][1])
2032 for b in bonus:
2033 d += int(bonus[b])
2034 bonus = str(d)
2035 if path[step+2] == None: self.data = bonus
2036 else:
2037 weapons = node.find('attacks')
2038 weapons = weapons.findall('weapon')
2039 for child in weapons:
2040 if path[step+2].lower() == child.get('name').lower():
2041 self.data = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']'
2042 return
2043 elif pc_stats.has_key(path[step].title()):
2044 if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')'
2045 elif path[step+1].title() == 'Mod': self.data = 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])+']'
2047 return