4847 lines
		
	
	
		
			207 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			4847 lines
		
	
	
		
			207 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import thread, time, os, urllib, random, re , platform, subprocess
 | |
| import charselect, ini, AOsocket, images, packets, demo, buttons
 | |
| 
 | |
| from os.path import exists, basename
 | |
| from ConfigParserEdit import ConfigParser
 | |
| from constants import *
 | |
| from collections import OrderedDict
 | |
| from pybass_constants import *
 | |
| from PyQt4 import QtGui, QtCore
 | |
| from functools import partial
 | |
| from ctypes import create_string_buffer
 | |
| from urllib2 import Request, urlopen
 | |
| 
 | |
| DOWNLOAD_BLACKLIST = []
 | |
| 
 | |
| URL_REGEX = r"https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)"
 | |
| 
 | |
| bucket = ""
 | |
| 
 | |
| def delay(msec):
 | |
|     dieTime = QtCore.QTime.currentTime().addMSecs(msec)
 | |
|     
 | |
|     while QtCore.QTime.currentTime() < dieTime:
 | |
|         QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
 | |
| 
 | |
| def getCharIni(char, section, value, default=""):
 | |
|     tempini = ConfigParser()
 | |
|     return ini.read_ini(AOpath + 'characters/' + char.lower() + '/char.ini', section, value, default)
 | |
| 
 | |
| def getOption(section, value, default=""):
 | |
|     tempini = ConfigParser()
 | |
|     tempini.read("AO2XP.ini")
 | |
|     return ini.read_ini(tempini, section, value, default)
 | |
| 
 | |
| def getImageSuffix(path):
 | |
|     if exists(path): return path
 | |
|     if exists(path+".webp"): return path+".webp"
 | |
|     if exists(path+".apng"): return path+".apng"
 | |
|     if exists(path+".gif"): return path+".gif"
 | |
|     return path+".png"
 | |
| 
 | |
| def getTextColor(textColor):
 | |
|     if textColor == 0 or textColor == 6:
 | |
|         return QtGui.QColor(255, 255, 255)
 | |
|     elif textColor == 1:
 | |
|         return QtGui.QColor(0, 255, 0)
 | |
|     elif textColor == 2:
 | |
|         return QtGui.QColor(255, 0, 0)
 | |
|     elif textColor == 3:
 | |
|         return QtGui.QColor(255, 165, 0)
 | |
|     elif textColor == 4:
 | |
|         return QtGui.QColor(45, 150, 255)
 | |
|     elif textColor == 5:
 | |
|         return QtGui.QColor(255, 255, 0)
 | |
|     elif textColor == 7:
 | |
|         return QtGui.QColor(255, 192, 203)
 | |
|     elif textColor == 8:
 | |
|         return QtGui.QColor(0, 255, 255)
 | |
|     elif textColor == "_inline_grey":
 | |
|         return QtGui.QColor(187, 187, 187)
 | |
|     
 | |
|     return QtGui.QColor(0, 0, 0)
 | |
| 
 | |
| def testPath(*args):
 | |
|     for path in args:
 | |
|         if exists(path):
 | |
|             return path
 | |
|     return False
 | |
| 
 | |
| def downloadThread(link, savepath):
 | |
|     global DOWNLOAD_BLACKLIST
 | |
|     if link in DOWNLOAD_BLACKLIST:
 | |
|         return
 | |
| 
 | |
|     print "[client] Download missing: %s" % link
 | |
|     fp = urllib.urlopen(bucket + link)
 | |
|     if fp.getcode() == 200:
 | |
|         print savepath[:-1]
 | |
|         if not os.path.exists(savepath[:-1]):
 | |
|             os.makedirs(savepath[:-1])
 | |
| 
 | |
|         with open(savepath, "wb") as f:
 | |
|             f.write(fp.read())
 | |
|         print "successfully downloaded:", link
 | |
|         return
 | |
| 
 | |
|     DOWNLOAD_BLACKLIST.append(link)
 | |
|     print "couldn't download '%s'" % link
 | |
|    
 | |
| def mockString(text):
 | |
|     upper = random.choice([True, False])
 | |
|     if isinstance(text, QtCore.QString):
 | |
|         l = QtCore.QStringList(list(text))
 | |
|         for i in range(len(text)):
 | |
|             if text[i] == " ":
 | |
|                 continue
 | |
|             
 | |
|             l[i] = l[i].toUpper() if upper else l[i].toLower()
 | |
|             upper = not upper
 | |
|         return l.join("")
 | |
|     else:
 | |
|         l = list(text)
 | |
|         for i in range(len(text)):
 | |
|             if text[i] == " ":
 | |
|                 continue
 | |
|             
 | |
|             l[i] = l[i].upper() if upper else l[i].lower()
 | |
|             upper = not upper
 | |
|         return "".join(l)
 | |
|  
 | |
| class MusicDownloadThread(QtCore.QThread):
 | |
|     # Part of the evil HTTPS music download hack for XP systems
 | |
|     finished_signal = QtCore.pyqtSignal(int, str)
 | |
| 
 | |
|     def __init__(self, caller, url):
 | |
|         super(MusicDownloadThread, self).__init__()
 | |
|         self.caller = caller
 | |
|         self.url = url
 | |
|         self.exiting = False
 | |
| 
 | |
|     def run(self):
 | |
|         self.exiting = False
 | |
|         self.download(self.url)
 | |
| 
 | |
|     def download(self, url):
 | |
|         if self.exiting:
 | |
|             return
 | |
|             
 | |
|         headers = {
 | |
|             'User-Agent': "AO2XP %s" % (GAME_VERSION),
 | |
|             'Accept': '*/*',
 | |
|             'Accept-Encoding': 'gzip, deflate',
 | |
|             'Accept-Language': 'en-US,en;q=0.9',
 | |
|             'Connection': 'keep-alive',
 | |
|             'Upgrade-Insecure-Requests': '1'
 | |
|         }
 | |
|         
 | |
|         request = Request(url, headers=headers)
 | |
|         request.get_method = lambda: 'HEAD'
 | |
|         try:
 | |
|             response = urlopen(request, timeout=5)
 | |
|         except Exception as e:
 | |
|             print "[audio] HTTP request failed, aborting... Details below:"
 | |
|             print "[audio]", e, url
 | |
|             self.quit()
 | |
|             return
 | |
|         
 | |
|         file_length = int(response.headers.get('Content-Length', 0))
 | |
| 
 | |
|         if file_length > 0:
 | |
|             request = Request(url, headers=headers)
 | |
|             response = urlopen(request)
 | |
|             stream = ""
 | |
|             
 | |
|             bytes_downloaded = 0
 | |
|             buffer_size = 8192
 | |
|             
 | |
|             while bytes_downloaded < file_length:
 | |
|                 if self.exiting:
 | |
|                     self.quit()
 | |
|                     break
 | |
|                 
 | |
|                 chunk = response.read(buffer_size)
 | |
|                 if not chunk:
 | |
|                     break
 | |
|                     
 | |
|                 stream += chunk
 | |
|                 bytes_downloaded += len(chunk)
 | |
|             
 | |
|             if not self.exiting:
 | |
|                 self.caller.stream = create_string_buffer(stream)
 | |
|                 self.finished_signal.emit(file_length, self.url)
 | |
|         else:
 | |
|             print "[audio] Stream is empty, aborting..."
 | |
|             self.quit()
 | |
|             return
 | |
|             
 | |
|     def stop(self):
 | |
|         self.exiting = True
 | |
| 
 | |
| class ChatLogs(QtGui.QTextEdit):
 | |
|     def __init__(self, parent, logtype, logfile=None):
 | |
|         QtGui.QTextEdit.__init__(self, parent)
 | |
|         self.type = logtype
 | |
|         #self.setMouseTracking(True)
 | |
|         self.logfile = None
 | |
|         self.anchor = None
 | |
|         self.savelog = False
 | |
|         self.combinelog = False
 | |
|         self.setLogFiles(logfile)
 | |
|             
 | |
|     def setLogFiles(self, logfile=None):
 | |
|         self.savelog = ini.read_ini_bool("AO2XP.ini", "General", "save logs")
 | |
|         self.combinelog = ini.read_ini_bool("AO2XP.ini", "General", "combined logs")
 | |
|         
 | |
|         if not exists("logs"):
 | |
|             os.mkdir("logs")
 | |
|         
 | |
|         if not self.logfile:
 | |
|             currtime = time.localtime()
 | |
|             if self.combinelog:
 | |
|                 if self.type == 0:
 | |
|                     self.logfile = logfile
 | |
|                 else:
 | |
|                     self.logfile = "logs/%d-%02d-%02d %02d.%02d.%02d.log" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5])
 | |
|             else:
 | |
|                 if self.type == 0:
 | |
|                     self.logfile = "logs/%d-%02d-%02d %02d.%02d.%02d [IC].log" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5])
 | |
|                 else:
 | |
|                     self.logfile = "logs/%d-%02d-%02d %02d.%02d.%02d [OOC].log" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5])
 | |
|         else:
 | |
|             self.logfile = None
 | |
|             
 | |
|     def __del__(self):
 | |
|         if self.savelog:
 | |
|             self.logfile.close()
 | |
|     
 | |
|     def append(self, text):
 | |
|         if self.savelog and not "Log started" in text:
 | |
|             with open(self.logfile, "a") as logfile:
 | |
|                 if isinstance(text, str) or isinstance(text, unicode):
 | |
|                     text_ = text.encode("utf-8")
 | |
|                     if self.combinelog:
 | |
|                         if self.type == 0:
 | |
|                             logfile.write("[IC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
 | |
|                         else:
 | |
|                             logfile.write("[OOC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
 | |
|                     else:
 | |
|                         logfile.write(text_.replace("<b>", "").replace("</b>", "") + "\n")
 | |
|                 else:
 | |
|                     text_ = text.toUtf8()
 | |
|                     if self.combinelog:
 | |
|                         if self.type == 0:
 | |
|                             logfile.write("[IC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
 | |
|                         else:
 | |
|                             logfile.write("[OOC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
 | |
|                     else:
 | |
|                         logfile.write(text_.replace("<b>", "").replace("</b>", "") +"\n")
 | |
|                         
 | |
|         super(ChatLogs, self).append(text)
 | |
| 
 | |
| class AOCharMovie(QtGui.QLabel):
 | |
|     done = QtCore.pyqtSignal()
 | |
|     usePillow = 0
 | |
|     pillowFrames = []
 | |
|     pillowFrame = 0
 | |
|     pillowSpeed = 0
 | |
|     xx = 0 # for restoring from screenshake
 | |
|     yy = 0 # for restoring from screenshake
 | |
| 
 | |
|     def __init__(self, parent, gameview):
 | |
|         QtGui.QLabel.__init__(self, parent)
 | |
|         
 | |
|         self.parent = parent
 | |
|         self.gameview = gameview
 | |
|         self.setAlignment(QtCore.Qt.AlignCenter)
 | |
|         self.timeMod = 60
 | |
|         self.playOnce = True
 | |
|         self.mFlipped = False
 | |
|         self.scaling = SCALING_AUTO
 | |
|         self.showOnPlay = True
 | |
|         
 | |
|         self.mMovie = QtGui.QMovie()
 | |
|         
 | |
|         self.preanimTimer = QtCore.QTimer(self)
 | |
|         self.preanimTimer.setSingleShot(True)
 | |
|         self.pillowTimer = QtCore.QTimer(self)
 | |
|         self.pillowTimer.setSingleShot(True)
 | |
| 
 | |
|         self.preanimTimer.timeout.connect(self.timer_done)
 | |
|         self.pillowTimer.timeout.connect(self.pillowFrameChange)
 | |
|         self.mMovie.frameChanged.connect(self.frameChange)
 | |
|         
 | |
|         self.prevGifPath = ""
 | |
|     
 | |
|     def resize(self):
 | |
|         super(AOCharMovie, self).resize(self.parent.size())
 | |
| 
 | |
|     def move(self, x, y, screenShaking=False):
 | |
|         if not screenShaking:
 | |
|             self.xx = x
 | |
|             self.yy = y
 | |
|         super(AOCharMovie, self).move(x, y)
 | |
|         
 | |
|     def moveSlide(self, x):
 | |
|         super(AOCharMovie, self).move(x, self.y())
 | |
|     
 | |
|     def setFlipped(self, flip):
 | |
|         self.mFlipped = flip
 | |
|     
 | |
|     def play(self, pChar, pEmote, emotePrefix, scaling = SCALING_AUTO, singleFrameDuration = -1):
 | |
|         if not len(pEmote):
 | |
|             return
 | |
|             
 | |
|         if pEmote[0] == "/" or pEmote[0] == "/":
 | |
|             pEmote = pEmote[1:]
 | |
|         elif "../../characters" in pEmote:
 | |
|             a = pEmote.split("/")
 | |
|             pChar = a[3]
 | |
|             emote = a[4]
 | |
|             emotePrefix = ""
 | |
|             pEmote = emote
 | |
|         
 | |
|         self.pillowFrames = []
 | |
|         self.pillowFrame = 0
 | |
|         
 | |
|         self.scaling = scaling
 | |
|         
 | |
|         pChar = pChar.lower()
 | |
|         pEmote = pEmote.lower()
 | |
| 
 | |
|         apngPath = testPath(
 | |
|             AOpath + "characters/" + pChar + "/" + emotePrefix + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/" + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/(a)" + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/(b)" + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/(a)/" + pEmote + ".apng",
 | |
|             AOpath + "characters/" + pChar + "/(b)/" + pEmote + ".apng"
 | |
|         )
 | |
|         
 | |
|         placeholderPath = AO2XPpath + "themes/default/oldplaceholder.gif"
 | |
|         
 | |
|         imgPath = ""
 | |
|         downloadCharacters = ini.read_ini_bool("AO2XP.ini", "General", "download characters")
 | |
|         
 | |
|         if apngPath:
 | |
|             imgPath = apngPath
 | |
|             self.usePillow = 1
 | |
|         else:
 | |
|             if downloadCharacters:
 | |
|                 url = "base/characters/" + pChar.lower() + "/" + emotePrefix + pEmote.lower() + ".apng"
 | |
|                 url = url.replace(" ", "%20")
 | |
|                 thread.start_new_thread(downloadThread, (url, apngPath))
 | |
|              
 | |
|             pngPath = testPath(
 | |
|                 AOpath + "characters/" + pChar + "/" + emotePrefix + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/" + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/(a)" + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/(b)" + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/(a)/" + pEmote + ".png",
 | |
|                 AOpath + "characters/" + pChar + "/(b)/" + pEmote + ".png"
 | |
|             )
 | |
| 
 | |
|             if pngPath:
 | |
|                 imgPath = pngPath
 | |
|                 self.usePillow = 0
 | |
|             else:
 | |
|                 if downloadCharacters:
 | |
|                     url = "base/characters/" + pChar.lower() + "/" + emotePrefix + pEmote.lower() + ".png"
 | |
|                     url = url.replace(" ", "%20")
 | |
|                     thread.start_new_thread(downloadThread, (url, pngPath))
 | |
|                     
 | |
|                 webpPath = testPath(
 | |
|                     AOpath + "characters/" + pChar + "/" + emotePrefix + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/" + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/(a)" + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/(b)" + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/(a)/" + pEmote + ".webp",
 | |
|                     AOpath + "characters/" + pChar + "/(b)/" + pEmote + ".webp"
 | |
|                 )
 | |
|                         
 | |
|                 if webpPath:
 | |
|                     imgPath = webpPath
 | |
|                     self.usePillow = 2
 | |
|                 else:
 | |
|                     if downloadCharacters:
 | |
|                         url = "base/characters/" + pChar.lower() + "/"+pEmote.lower() + ".webp"
 | |
|                         url = url.replace(" ", "%20")
 | |
|                         thread.start_new_thread(downloadThread, (url, webpPath))
 | |
|                         
 | |
|                     gifPath = testPath(
 | |
|                         AOpath + "characters/" + pChar + "/" + emotePrefix + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/" + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/(a)" + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/(b)" + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/(a)/" + pEmote + ".gif",
 | |
|                         AOpath + "characters/" + pChar + "/(b)/" + pEmote + ".gif"
 | |
|                     )
 | |
|                         
 | |
|                     if gifPath:
 | |
|                         imgPath = gifPath
 | |
|                         self.usePillow = 0
 | |
|                     else:
 | |
|                         if downloadCharacters:
 | |
|                             url = "base/characters/" + pChar.lower() + "/" + emotePrefix + pEmote.lower() + ".gif"
 | |
|                             url = url.replace(" ", "%20")
 | |
|                             thread.start_new_thread(downloadThread, (url, gifPath))
 | |
| 
 | |
|                         if exists(placeholderPath):
 | |
|                             imgPath = placeholderPath
 | |
|                             print "[debug] Sprite not found:", pChar, pEmote, emotePrefix
 | |
|                         else:
 | |
|                             imgPath = ""
 | |
|                         self.usePillow = 0
 | |
|     
 | |
|         if imgPath == "":
 | |
|             imgPath = self.prevGifPath
 | |
|             # Second check just in case
 | |
|             if imgPath == "":
 | |
|                 if exists(placeholderPath):
 | |
|                     imgPath = placeholderPath
 | |
|                     print "[debug] Sprite not found: ", pChar, pEmote, emotePrefix
 | |
|                 else:
 | |
|                     imgPath = "placeholder.png"
 | |
|         else:
 | |
|             self.prevGifPath = imgPath
 | |
|         
 | |
|         #print "[debug]", pChar, emotePrefix, pEmote, "(!) path is null!" if imgPath == "" else imgPath
 | |
| 
 | |
|         if not self.usePillow:
 | |
|             self.mMovie.setFileName(imgPath)
 | |
|             self.mMovie.start()
 | |
|         elif self.usePillow == 1: # apng
 | |
|             self.pillowFrames = images.load_apng(apngPath)
 | |
|             if len(self.pillowFrames) > 1:
 | |
|                 self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
 | |
|             else:
 | |
|                 self.pillowTimer.start(int(singleFrameDuration * self.pillowSpeed))
 | |
|                 
 | |
|             self.setPillowFrame()
 | |
|         elif self.usePillow == 2: # webp
 | |
|             try:
 | |
|                 self.pillowFrames = images.load_webp(webpPath)
 | |
|                 if len(self.pillowFrames) > 1:
 | |
|                     self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
 | |
|                 else:
 | |
|                     self.pillowTimer.start(int(singleFrameDuration * self.pillowSpeed))
 | |
|                     
 | |
|                 self.setPillowFrame()
 | |
|             except:
 | |
|                 if exists(placeholderPath):
 | |
|                     imgPath = placeholderPath
 | |
|                     print "[debug] Couldn't load webp sprite!"
 | |
|                 else:
 | |
|                     imgPath = "placeholder.png"
 | |
|                 self.mMovie.setFileName(imgPath)
 | |
|                 self.mMovie.start()
 | |
|         
 | |
|         if self.showOnPlay:
 | |
|             self.show()
 | |
|     
 | |
|     def playPre(self, pChar, pEmote, duration, scaling = SCALING_AUTO):
 | |
|         pChar = pChar.lower()
 | |
|         
 | |
|         gifPath = AOpath + "characters/" + pChar + "/" + pEmote + ".gif"
 | |
|         apngPath = AOpath + "characters/" + pChar + "/" + pEmote + ".apng"
 | |
|         webpPath = AOpath + "characters/" + pChar + "/" + pEmote + ".webp"
 | |
|    
 | |
|         fullDuration = duration * self.timeMod
 | |
|         realDuration = 0
 | |
|         
 | |
|         self.playOnce = False
 | |
|         self.mMovie.stop()
 | |
|         self.clear()
 | |
| 
 | |
|         if exists(apngPath):
 | |
|             realDuration = images.get_apng_duration(apngPath)
 | |
|         elif exists(webpPath):
 | |
|             realDuration = images.get_webp_duration(webpPath)
 | |
|         elif exists(gifPath):
 | |
|             self.mMovie.setFileName(gifPath)
 | |
|             self.mMovie.jumpToFrame(0)
 | |
|             for nFrame in range(self.mMovie.frameCount()):
 | |
|                 realDuration += self.mMovie.nextFrameDelay()
 | |
|                 self.mMovie.jumpToFrame(nFrame + 1)
 | |
|         
 | |
|         percentageModifier = 100.0
 | |
|         
 | |
|         if realDuration != 0 and duration != 0:
 | |
|             modifier = fullDuration / float(realDuration)
 | |
|             percentageModifier = 100 / modifier
 | |
|             
 | |
|             if percentageModifier > 100.0 or percentageModifier < 0.0:
 | |
|                 percentageModifier = 100.0
 | |
|         
 | |
|         self.pillow_fullduration = fullDuration
 | |
|         if fullDuration == 0 or fullDuration >= realDuration:
 | |
|             self.playOnce = True
 | |
|         else:
 | |
|             self.playOnce = False
 | |
|             if fullDuration >= 0:
 | |
|                 self.preanimTimer.start(fullDuration)
 | |
|         
 | |
|         self.mMovie.setSpeed(int(percentageModifier))
 | |
| 
 | |
|         self.pillowSpeed = percentageModifier / 100.
 | |
|         if realDuration > 0:
 | |
|             self.play(pChar, pEmote, "", scaling)
 | |
|         else:
 | |
|             self.play(pChar, pEmote, "", scaling, fullDuration)
 | |
|     
 | |
|     def playTalking(self, pChar, pEmote, scaling = SCALING_AUTO):
 | |
|         pChar = pChar.lower()
 | |
|         gifPath = AOpath + 'characters/' + pChar + '/(b)' + pEmote + '.gif'
 | |
|         
 | |
|         self.mMovie.stop()
 | |
|         self.clear()
 | |
|         self.mMovie.setFileName(gifPath)
 | |
|         self.mMovie.jumpToFrame(0)
 | |
|         
 | |
|         self.playOnce = False
 | |
|         self.mMovie.setSpeed(100)
 | |
|         self.pillowSpeed = 1
 | |
|         self.play(pChar, pEmote, '(b)', scaling)
 | |
| 
 | |
|     def playIdle(self, pChar, pEmote, scaling = SCALING_AUTO):
 | |
|         pChar = pChar.lower()
 | |
|         gifPath = AOpath + 'characters/' + pChar + '/(a)' + pEmote + '.gif'
 | |
|         
 | |
|         self.mMovie.stop()
 | |
|         self.clear()
 | |
|         self.mMovie.setFileName(gifPath)
 | |
|         self.mMovie.jumpToFrame(0)
 | |
|         
 | |
|         self.playOnce = False
 | |
|         self.mMovie.setSpeed(100)
 | |
|         self.pillowSpeed = 1
 | |
|         self.play(pChar, pEmote, '(a)', scaling)
 | |
| 
 | |
|     def stop(self):
 | |
|         self.mMovie.stop()
 | |
|         self.preanimTimer.stop()
 | |
|         self.hide()
 | |
|     
 | |
|     def getTransform(self, smooth_condition=True):
 | |
|         if self.scaling == SCALING_PIXEL:
 | |
|             return QtCore.Qt.FastTransformation
 | |
|         elif self.scaling == SCALING_SMOOTH:
 | |
|             return QtCore.Qt.SmoothTransformation
 | |
|         elif smooth_condition:
 | |
|             return QtCore.Qt.SmoothTransformation
 | |
|         else:
 | |
|             return QtCore.Qt.FastTransformation
 | |
|             
 | |
|     def getAspect(self, size):
 | |
|         if size.width() / float(size.height()) >= self.gameview.viewportRatio:
 | |
|             return QtCore.Qt.KeepAspectRatioByExpanding
 | |
|         else:
 | |
|             return QtCore.Qt.KeepAspectRatio
 | |
|     
 | |
|     def getScaledImage(self, f_img):
 | |
|         if not f_img.isNull():
 | |
|             transform = self.getTransform(f_img.size().height() > self.size().height())
 | |
|             aspect = self.getAspect(f_img.size())
 | |
|             return f_img.scaled(self.size(), aspect, transform)
 | |
|         return f_img
 | |
| 
 | |
|     @QtCore.pyqtSlot(int)
 | |
|     def frameChange(self, nFrame):
 | |
|         f_img = self.getScaledImage(self.mMovie.currentImage().mirrored(self.mFlipped, False))
 | |
| 
 | |
|         fPixmap = QtGui.QPixmap.fromImage(f_img)
 | |
|         self.setPixmap(fPixmap)
 | |
|         
 | |
|         if self.mMovie.frameCount() - 1 == nFrame and self.playOnce:
 | |
|             self.preanimTimer.start(self.mMovie.nextFrameDelay())
 | |
| 
 | |
|     @QtCore.pyqtSlot()
 | |
|     def pillowFrameChange(self):
 | |
|         if not self.pillowFrames: return
 | |
| 
 | |
|         if len(self.pillowFrames) - 1 == self.pillowFrame:
 | |
|             if self.playOnce:
 | |
|                 self.preanimTimer.start(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
|             elif len(self.pillowFrames) > 1:
 | |
|                 self.pillowFrame = 0
 | |
|                 self.pillowTimer.start(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
|         else:
 | |
|             self.pillowFrame += 1
 | |
|             self.pillowTimer.start(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
| 
 | |
|         self.setPillowFrame()
 | |
| 
 | |
|     def setPillowFrame(self):
 | |
|         f_img = self.getScaledImage(self.pillowFrames[self.pillowFrame][0].mirrored(self.mFlipped, False))
 | |
|         
 | |
|         fPixmap = QtGui.QPixmap.fromImage(f_img)
 | |
|         self.setPixmap(fPixmap)
 | |
| 
 | |
|     @QtCore.pyqtSlot()
 | |
|     def timer_done(self):
 | |
|         self.done.emit()
 | |
| 
 | |
| class AOMovie(QtGui.QLabel):
 | |
|     playOnce = True
 | |
|     done = QtCore.pyqtSignal()
 | |
|     usePillow = 0
 | |
|     pillowFrames = []
 | |
|     pillowFrame = 0
 | |
|     pillowSpeed = 1
 | |
|     pillowLoops = 0
 | |
|     xx = 0 # for restoring from screenshake
 | |
|     yy = 0 # for restoring from screenshake
 | |
| 
 | |
|     def __init__(self, parent):
 | |
|         QtGui.QLabel.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.mMovie = QtGui.QMovie()
 | |
|         self.setMovie(self.mMovie)
 | |
|         self.mMovie.frameChanged.connect(self.frameChange)
 | |
| 
 | |
|         self.pillowTimer = QtCore.QTimer(self)
 | |
|         self.pillowTimer.setSingleShot(True)
 | |
|         self.pillowTimer.timeout.connect(self.pillowFrameChange)
 | |
|         
 | |
|         self.pillowLabel = QtGui.QLabel(self)
 | |
|         self.pillowLabel.hide()
 | |
|         
 | |
|     def resize(self):
 | |
|         super(AOMovie, self).resize(self.parent.size())
 | |
|         self.pillowLabel.setGeometry(0, 0, self.parent.size().width(), self.parent.size().height())
 | |
| 
 | |
|     def move(self, x, y):
 | |
|         self.xx = x
 | |
|         self.yy = y
 | |
|         super(AOMovie, self).move(x, y)
 | |
| 
 | |
|     def setPlayOnce(self, once):
 | |
|         self.playOnce = once
 | |
|     
 | |
|     def play(self, pImage, pChar=""):
 | |
|         gifPath = pImage
 | |
|         pillowModes = {".gif": 0, ".apng": 1, ".webp": 2, ".png": 1}
 | |
|         
 | |
|         pImage = unicode(pImage)
 | |
|         
 | |
|         if not exists(gifPath):
 | |
|             pathlist = [
 | |
|                 getImageSuffix(AO2XPpath + "themes/default/" + pImage + "_bubble"),
 | |
|                 getImageSuffix(AOpath + "characters/" + pChar + "/" + pImage),
 | |
|                 getImageSuffix(AOpath + "misc/default/" + pImage),
 | |
|                 getImageSuffix(AO2XPpath + "themes/default/" + pImage)
 | |
|                 ]
 | |
|             
 | |
|             for f in pathlist:
 | |
|                 if exists(f):
 | |
|                     gifPath = f
 | |
|                     break
 | |
|         
 | |
|         if not exists(gifPath):
 | |
|             self.done.emit()
 | |
|             return
 | |
| 
 | |
|         self.usePillow = pillowModes[os.path.splitext(gifPath)[1]]
 | |
|         
 | |
|         if not self.usePillow:
 | |
|             self.mMovie.setFileName(gifPath)
 | |
|             self.mMovie.start()
 | |
|         elif self.usePillow == 1: # apng
 | |
|             self.pillowLabel.show()
 | |
|             self.pillowFrames = images.load_apng(gifPath)
 | |
|             #if len(self.pillowFrames) > 1:
 | |
|             self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
 | |
|             self.setPillowFrame()
 | |
|         elif self.usePillow == 2: # webp
 | |
|             self.pillowLabel.show()
 | |
|             self.pillowLoops = 0
 | |
|             self.pillowFrames, self.webpLoops = images.load_webp(gifPath)
 | |
|             #if len(self.pillowFrames) > 1:
 | |
|             self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
 | |
|             self.setPillowFrame()
 | |
| 
 | |
|         self.show()
 | |
|     
 | |
|     def stop(self):
 | |
|         self.pillowFrames = []
 | |
|         self.pillowFrame = 0
 | |
|         self.pillowTimer.stop()
 | |
|         self.mMovie.stop()
 | |
|         self.pillowLabel.clear()
 | |
|         self.pillowLabel.hide()
 | |
|         self.hide()
 | |
|     
 | |
|     @QtCore.pyqtSlot(int)
 | |
|     def frameChange(self, nFrame):
 | |
|         if nFrame == self.mMovie.frameCount() - 1 and self.playOnce:
 | |
|             delay(self.mMovie.nextFrameDelay())
 | |
|             self.stop()
 | |
|             self.done.emit()
 | |
| 
 | |
|     @QtCore.pyqtSlot()
 | |
|     def pillowFrameChange(self):
 | |
|         if not self.pillowFrames: return
 | |
| 
 | |
|         if len(self.pillowFrames) - 1 == self.pillowFrame:
 | |
|             if self.playOnce or (self.usePillow == 2 and self.pillowLoops+1 == self.webpLoops):
 | |
|                 delay(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
|                 self.stop()
 | |
|                 self.done.emit()
 | |
|             elif len(self.pillowFrames) > 1: # loop
 | |
|                 self.pillowLoops += 1
 | |
|                 self.pillowFrame = 0
 | |
|                 self.pillowTimer.start(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
|         elif len(self.pillowFrames) > 1:
 | |
|             self.pillowFrame += 1
 | |
|             self.pillowTimer.start(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
 | |
| 
 | |
|         self.setPillowFrame()
 | |
| 
 | |
|     def setPillowFrame(self):
 | |
|         if not self.pillowFrames: return
 | |
| 
 | |
|         f_img = self.pillowFrames[self.pillowFrame][0]
 | |
|         if not f_img.isNull() and (f_img.size().width() != self.size().width() or f_img.size().height() != self.size().height()):
 | |
|             f_img = f_img.scaled(self.size().width(), self.size().height(), QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)
 | |
| 
 | |
|         fPixmap = QtGui.QPixmap.fromImage(f_img)
 | |
|         self.pillowLabel.setPixmap(fPixmap)
 | |
| 
 | |
| class ZoomLines(QtGui.QLabel):
 | |
|     def __init__(self, parent):
 | |
|         super(ZoomLines, self).__init__(parent)
 | |
|         self.parent = parent
 | |
|         self.setScaledContents(True)
 | |
|         self.movie = QtGui.QMovie()
 | |
|         self.movie.frameChanged.connect(self.frameChange)
 | |
|         
 | |
|     def resize(self):
 | |
|         super(ZoomLines, self).resize(self.parent.size())
 | |
| 
 | |
|     def frameChange(self):
 | |
|         img = self.movie.currentImage()
 | |
|         self.setPixmap(QtGui.QPixmap.fromImage(img))
 | |
| 
 | |
|     def setZoom(self, on, dir=0):
 | |
|         self.movie.stop()
 | |
|         if not on:
 | |
|             self.hide()
 | |
|             return
 | |
|         self.show()
 | |
|         if dir == 0:
 | |
|             self.movie.setFileName(AO2XPpath + 'themes/default/defense_speedlines.gif')
 | |
|         else:
 | |
|             self.movie.setFileName(AO2XPpath + 'themes/default/prosecution_speedlines.gif')
 | |
|         self.movie.start()
 | |
| 
 | |
| class WTCEView(QtGui.QLabel):
 | |
|     def __init__(self, parent):
 | |
|         super(WTCEView, self).__init__(parent)
 | |
|         self.parent = parent
 | |
|         self.movie = QtGui.QMovie()
 | |
|         self.movie.frameChanged.connect(self.frameChange)
 | |
|         self.finalframeTimer = QtCore.QTimer()
 | |
|         self.finalframeTimer.setSingleShot(False)
 | |
|         self.finalframeTimer.timeout.connect(self.finished)
 | |
|         
 | |
|     def resize(self):
 | |
|         super(WTCEView, self).move(self.parent.viewport.x(), self.parent.viewport.y())
 | |
|         super(WTCEView, self).resize(self.parent.viewport.size())
 | |
| 
 | |
|     def frameChange(self, frame):
 | |
|         if self.movie.state() != QtGui.QMovie.Running:
 | |
|             return
 | |
|         img = self.movie.currentImage()
 | |
|         pixmap = QtGui.QPixmap.fromImage(img)
 | |
|         if not pixmap.isNull():
 | |
|             self.setPixmap(pixmap.scaled(self.size().width(), self.size().height(), QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
|         if self.movie.currentFrameNumber() == self.movie.frameCount() - 1:
 | |
|             self.finalframeTimer.start(self.movie.nextFrameDelay())
 | |
| 
 | |
|     def finished(self):
 | |
|         self.finalframeTimer.stop()
 | |
|         self.movie.stop()
 | |
|         self.hide()
 | |
| 
 | |
|     def showWTCE(self, wtce, variant=0):
 | |
|         self.finished()
 | |
|         if wtce == 'testimony1':
 | |
|             self.movie.setFileName(AO2XPpath + 'themes/default/witnesstestimony.gif')
 | |
|         elif wtce == 'testimony2':
 | |
|             self.movie.setFileName(AO2XPpath + 'themes/default/crossexamination.gif')
 | |
|         elif wtce == "judgeruling":
 | |
|             if variant == 0:
 | |
|                 self.movie.setFileName(AO2XPpath + 'themes/default/notguilty.gif')
 | |
|             elif variant == 1:
 | |
|                 self.movie.setFileName(AO2XPpath + 'themes/default/guilty.gif')
 | |
|         else:
 | |
|             return
 | |
|         self.show()
 | |
|         self.movie.start()
 | |
| 
 | |
| class EditEvidenceDialog(QtGui.QDialog):
 | |
|     def __init__(self, gamegui):
 | |
|         super(EditEvidenceDialog, self).__init__()
 | |
|         self.gamegui = gamegui
 | |
|         self.setTitle()
 | |
|         self.resize(512, 384)
 | |
|         self.setModal(True)
 | |
| 
 | |
|         self.eviname = QtGui.QLineEdit(self)
 | |
|         self.eviname.setGeometry(8, 8, 410, 24)
 | |
|         self.evidesc = QtGui.QTextEdit(self)
 | |
|         self.evidesc.setGeometry(8, 192 - 105, 496, 255)
 | |
|         self.evidesc.setAcceptRichText(False)
 | |
|         self.evipicture = QtGui.QLabel(self)
 | |
|         self.filename = 'empty.png'
 | |
|         evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png')
 | |
|         self.evipicture.setPixmap(evipic)
 | |
|         self.evipicture.move(434, 8)
 | |
|         self.evipicture.show()
 | |
|         
 | |
|         self.save = QtGui.QPushButton(self)
 | |
|         self.save.setText('Save')
 | |
|         self.save.clicked.connect(self.onSaveClicked)
 | |
|         self.save.move(256 - self.save.size().width() - 8, 384 - self.save.size().height() - 2)
 | |
|         self.cancel = QtGui.QPushButton(self)
 | |
|         self.cancel.setText('Cancel')
 | |
|         self.cancel.clicked.connect(self.onCancelClicked)
 | |
|         self.cancel.move(264 + 16, 384 - self.cancel.size().height() - 2)
 | |
|         self.choosepic = QtGui.QComboBox(self)
 | |
|         self.choosepic.setEditable(True)
 | |
|         self.choosepic.setGeometry(self.eviname.x() + self.eviname.size().width() - 128 - 84, self.eviname.y() + 70 - 32, 128, 24)
 | |
|         self.filenames = []
 | |
|         self.browse = QtGui.QPushButton(self)
 | |
|         self.browse.setText('Browse')
 | |
|         self.browse.clicked.connect(self.onBrowseClicked)
 | |
|         self.browse.move(self.choosepic.x() + self.choosepic.width() + 8, self.choosepic.y())
 | |
|         
 | |
|         files = os.listdir(AOpath + 'evidence')
 | |
|         fileslength = len(files)
 | |
|         i = 0
 | |
|         while i < fileslength:
 | |
|             if not files[i].endswith('.png'):
 | |
|                 del files[i]
 | |
|                 fileslength = len(files)
 | |
|                 i -= 1
 | |
|             i += 1
 | |
| 
 | |
|         for i in range(len(files)):
 | |
|             if files[i].endswith('.png'):
 | |
|                 self.choosepic.addItem(files[i].strip('.png'))
 | |
|                 self.filenames.append(files[i])
 | |
|                 if files[i].lower() == 'empty.png':
 | |
|                     self.emptyfile = i
 | |
| 
 | |
|         self.editing = False
 | |
|         self.choosepic.currentIndexChanged.connect(self.choosePicChange)
 | |
|         self.choosepic.setCurrentIndex(i)
 | |
| 
 | |
|     def choosePicChange(self, ind):
 | |
|         self.filename = self.filenames[ind]
 | |
|         if exists(AOpath + 'evidence/' + self.filename):
 | |
|             self.evipicture.setPixmap(QtGui.QPixmap(AOpath + 'evidence/' + self.filename))
 | |
|         else:
 | |
|             self.evipicture.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/evidence_selected.png'))
 | |
| 
 | |
|     def onSaveClicked(self):
 | |
|         name = encodeAOString(self.eviname.text())
 | |
|         desc = encodeAOString(self.evidesc.toPlainText())
 | |
| 
 | |
|         if not self.gamegui.privateInventorySelected:
 | |
|             if self.editing:
 | |
|                 self.gamegui.tcp.send('EE#' + str(self.editInd) + '#' + name + '#' + desc + '#' + self.filename + '#%')
 | |
|             else:
 | |
|                 self.gamegui.tcp.send('PE#' + name + '#' + desc + '#' + self.filename + '#%')
 | |
|         else:
 | |
|             if self.editing:
 | |
|                 self.gamegui.privateEvidence[self.gamegui.selectedEvidence] = [unicode(name), unicode(desc), unicode(self.filename)]
 | |
|                 self.gamegui.boxPrivateEvidence.setItemText(self.gamegui.selectedEvidence, name)
 | |
|                 
 | |
|                 evi = self.gamegui.privateEvidence[self.gamegui.selectedEvidence]
 | |
|                 self.gamegui.evidenceDescription.setText(evi[1])
 | |
|                 self.gamegui.setEvidenceImage(self.gamegui.evidenceImage, evi[2])
 | |
|             else:
 | |
|                 self.gamegui.privateEvidence.append([name, desc, self.filename])
 | |
|                 self.gamegui.boxPrivateEvidence.addItem(name)
 | |
|             self.gamegui.onExportEvidence(True)
 | |
| 
 | |
|         self.eviname.setText('')
 | |
|         self.evidesc.setText('')
 | |
|         evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png')
 | |
|         self.evipicture.setPixmap(evipic)
 | |
|         self.filename = 'empty.png'
 | |
|         self.editing = False
 | |
|         self.setTitle()
 | |
|         self.choosepic.setCurrentIndex(self.emptyfile)
 | |
|         self.hide()
 | |
| 
 | |
|     def onCancelClicked(self):
 | |
|         self.eviname.setText('')
 | |
|         self.evidesc.setText('')
 | |
|         evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png')
 | |
|         self.evipicture.setPixmap(evipic)
 | |
|         self.filename = 'empty.png'
 | |
|         self.editing = False
 | |
|         self.setTitle()
 | |
|         self.choosepic.setCurrentIndex(self.emptyfile)
 | |
|         self.hide()
 | |
|         
 | |
|     def onBrowseClicked(self):
 | |
|         path = str(QtGui.QFileDialog.getOpenFileName(self, "Select an image", AOpath + 'evidence', "Images (*.png)"))
 | |
|         if path:
 | |
|             if not "/evidence/" in path.lower():
 | |
|                 QtGui.QMessageBox.warning(self, 'Wrong directory', 'Please select a file from the "evidence" directory.')
 | |
|                 self.onBrowseClicked()
 | |
|                 return
 | |
|             
 | |
|             file = basename(path)
 | |
|             if file.lower().endswith('.png'):
 | |
|                 ind = os.listdir(AOpath + 'evidence').index(file)
 | |
|                 self.choosepic.setCurrentIndex(ind)
 | |
|             else:
 | |
|                 QtGui.QMessageBox.warning(self, 'Not a valid file', 'Please select a PNG image.')
 | |
|                 self.onBrowseClicked()
 | |
| 
 | |
|     def editEvidence(self, ind):
 | |
|         self.editing = True
 | |
|         self.editInd = ind
 | |
|         evidence = self.gamegui.privateEvidence if self.gamegui.privateInventorySelected else self.gamegui.evidence
 | |
|         
 | |
|         if evidence[ind][2] not in self.filenames:
 | |
|             self.filenames.append(evidence[ind][2])
 | |
|             self.choosepic.addItem(evidence[ind][2].split('.')[0])
 | |
|         self.choosepic.setCurrentIndex(self.filenames.index(evidence[ind][2]))
 | |
|         self.eviname.setText(evidence[ind][0])
 | |
|         self.evidesc.setText(evidence[ind][1])
 | |
|         self.setWindowTitle("Edit evidence" if not self.gamegui.privateInventorySelected else "Edit evidence in private inventory")
 | |
|         self.show()
 | |
|         
 | |
|     def setTitle(self):
 | |
|         self.setWindowTitle('Add evidence' if not self.gamegui.privateInventorySelected else "Add evidence to private inventory")
 | |
|   
 | |
| class TCPThread(QtCore.QThread):
 | |
|     connectionError = QtCore.pyqtSignal(str, str, str)
 | |
|     MS_Chat = QtCore.pyqtSignal(list)
 | |
|     newChar = QtCore.pyqtSignal(str)
 | |
|     newBackground = QtCore.pyqtSignal(str, bool)
 | |
|     IC_Log = QtCore.pyqtSignal(str)
 | |
|     OOC_Log = QtCore.pyqtSignal(str)
 | |
|     charSlots = QtCore.pyqtSignal()
 | |
|     showCharSelect = QtCore.pyqtSignal()
 | |
|     loadAllEvidence = QtCore.pyqtSignal(list)
 | |
|     rainbowColor = QtCore.pyqtSignal(str)
 | |
|     updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
 | |
|     timerUpdate = QtCore.pyqtSignal(int, int, int)
 | |
|     
 | |
|     send_attempts = 0
 | |
|     max_attempts = 5
 | |
|     stop_now = False
 | |
|     
 | |
|     def __init__(self, parent):
 | |
|         super(TCPThread, self).__init__(parent)
 | |
|         self.parent = parent
 | |
|         
 | |
|     def run(self):
 | |
|         pingtimer = 150
 | |
|         rainbow = 0
 | |
|         sendtick = 0
 | |
|         tempdata = ""
 | |
|         color = QtGui.QColor()
 | |
|         color.setHsv(rainbow, 255, 255)
 | |
|         while True:
 | |
|             if self.stop_now:
 | |
|                 self.parent.tcp.close()
 | |
|                 self.parent.tcp = None
 | |
|                 self.quit()
 | |
|                 return
 | |
|         
 | |
|             if self.parent.disconnectNow:
 | |
|                 self.parent.disconnectCommon()
 | |
|                 self.quit()
 | |
|                 return
 | |
|             pingtimer -= 1
 | |
| 
 | |
|             if pingtimer == 0:
 | |
|                 pingbefore = time.time()
 | |
|                 self.parent.tcp.send('CH#%')
 | |
|                 pingtimer = 150
 | |
|             
 | |
|             if self.parent.mChatMessage[TEXT_COLOR] == str(C_RAINBOW):
 | |
|                 color.setHsv(rainbow, 255, 255)
 | |
|                 rainbow += 5
 | |
|                 if rainbow > 255:
 | |
|                     rainbow = 0
 | |
|                 #self.parent.text.setStyleSheet('color: rgb(' + str(color.red()) + ', ' + str(color.green()) + ', ' + str(color.blue()) + ')')
 | |
|                 self.rainbowColor.emit('background-color: rgba(0, 0, 0, 0); color: rgb(' + str(color.red()) + ', ' + str(color.green()) + ', ' + str(color.blue()) + ')')
 | |
|                 
 | |
|             if sendtick:
 | |
|                 sendtick -= 1
 | |
|             if self.parent.messageQueue and not sendtick:
 | |
|                 self.parent.tcp.send(self.parent.messageQueue[0])
 | |
|                 sendtick = 4
 | |
| 
 | |
|             error, total = self.parent.tcp.recv()
 | |
|             if error == -2:
 | |
|                 # if the message can't be sent, discard it
 | |
|                 if sendtick == 4:
 | |
|                     self.send_attempts += 1
 | |
|                     if self.send_attempts >= self.max_attempts:
 | |
|                         self.send_attempts = 0
 | |
|                         #print "[warning] message discarded"
 | |
|                         del self.parent.messageQueue[0]
 | |
|                         self.parent.queueItems.takeItem(0)
 | |
|                 continue
 | |
|             elif error == -1:
 | |
|                 self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', "%s connection to server lost." % ("WebSocket" if self.parent.tcp.isWS else "TCP"))
 | |
|                 self.parent.willDisconnect = True
 | |
|                 self.quit()
 | |
|                 return
 | |
|             elif error == -3:
 | |
|                 self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', "There was a critical connection failure. Please check your internet connection.\n\nDetails: %s." % total)
 | |
|                 self.parent.willDisconnect = True
 | |
|                 self.quit()
 | |
|                 return
 | |
|             else:
 | |
|                 self.send_attempts = 0
 | |
|                 
 | |
|             packets.handlePackets(self, total)
 | |
|     
 | |
|     def stop(self):
 | |
|         self.stop_now = True
 | |
| 
 | |
| class Chatbox(QtGui.QLabel):
 | |
|     def __init__(self, parent):
 | |
|         QtGui.QLabel.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.initial = None
 | |
|         self.geometrySet = False
 | |
|     
 | |
|     def setGeometry(self, x, y, w, h):
 | |
|         if self.geometrySet:
 | |
|             return
 | |
|         self.geometrySet = True
 | |
|         super(Chatbox, self).setGeometry(x - self.parent.x(), y - self.parent.y(), w, h)
 | |
|         self.initial = self.geometry()
 | |
|         
 | |
|     def resetGeometry(self):
 | |
|         self.geometrySet = False
 | |
| 
 | |
| class GUI(QtGui.QWidget):
 | |
|     gamewindow = None
 | |
|     # In theory 3 sounds may play at the same time: character, evidence sweep,
 | |
|     # effect
 | |
|     soundChannels = 3 
 | |
|     soundChannel = 0
 | |
|     sound = []
 | |
|     for i in range(soundChannels):
 | |
|         sound.append(None)
 | |
|     music = None
 | |
|     nextCharacterIsNotSpecial = False
 | |
|     messageIsCentered = False
 | |
|     currentDisplaySpeed = 3
 | |
|     messageDisplaySpeed = (30, 40, 50, 60, 75, 100, 120)
 | |
|     entireMessageIsBlue = False
 | |
|     inlineColorStack = [] 
 | |
|     inlineBlueDepth = 0
 | |
|     otherCharId = -1
 | |
|     offsetWithPair = 0
 | |
|     tickPos = 0
 | |
|     blipPos = 0
 | |
|     blipRate = 1
 | |
|     timeMod = 40
 | |
|     blip = "male"
 | |
|     blipSound = None
 | |
|     chatMessageSize = 33
 | |
|     mChatMessage = []
 | |
|     blankBlip = False
 | |
|     chatMessageIsEmpty = False
 | |
|     animIsEmpty = False
 | |
|     lastSide = "wit"
 | |
|     isAdditive = False
 | |
|     additiveChar = -1
 | |
|     animState = 3
 | |
|     textState = 2
 | |
|     objectionState = 0
 | |
|     textColor = 0
 | |
|     
 | |
|     charini = ConfigParser()
 | |
|     chatmsg = ''
 | |
|     charid = -1
 | |
|     login = False
 | |
|     privateMusicSelected = False
 | |
|     privateInventorySelected = False
 | |
|     scaling = [SCALING_AUTO, SCALING_AUTO]
 | |
|    
 | |
|     wtceSignal = QtCore.pyqtSignal(str, int)
 | |
|     healthbars = QtCore.pyqtSignal(int, int)
 | |
|     gotPing = QtCore.pyqtSignal(int)
 | |
| 
 | |
|     def __init__(self, parent=None):
 | |
|         super(GUI, self).__init__(parent)
 | |
|         self.gamewindow = parent
 | |
|         
 | |
|         self.gotPing.connect(self.setPing)
 | |
|         
 | |
|         for i in range(self.chatMessageSize):
 | |
|             self.mChatMessage.append("")
 | |
|             
 | |
|         self.chatTickTimer = QtCore.QTimer(self)
 | |
|         self.chatTickTimer.timeout.connect(self.chatTick)
 | |
|         
 | |
|         self.sfxDelayTimer = QtCore.QTimer(self)
 | |
|         self.sfxDelayTimer.setSingleShot(True)
 | |
|         self.sfxDelayTimer.timeout.connect(self.playSfx)
 | |
|         
 | |
|         self.inboxTimer = QtCore.QTimer(self)
 | |
|         self.inboxTimer.setSingleShot(True)
 | |
|         self.inboxTimer.timeout.connect(self.inboxTimerTimeout)
 | |
|         
 | |
|         self.modcall = None
 | |
|         
 | |
|         self.healthbars.connect(self.netmsgHP)
 | |
|         self.disconnectNow = False
 | |
|         self.swapping = False
 | |
|         self.iniSwapIndex = 0
 | |
|         self.background = 'default'
 | |
|         self.viewportScale = 1
 | |
|         self.viewportRatio = 1
 | |
|         
 | |
|         self.viewport = QtGui.QWidget(self)
 | |
|         self.viewport.setObjectName("ui_viewport")
 | |
|         self.court = QtGui.QLabel(self.viewport)
 | |
|         
 | |
|         self.slideBg = QtGui.QLabel(self.viewport)
 | |
|         self.slideBgAnimation = QtCore.QPropertyAnimation(self.slideBg, "geometry")
 | |
|         self.slideBgAnimation.finished.connect(self.slideDone)
 | |
|         self.slideBgAnimation.valueChanged.connect(self.slideChanged)
 | |
|         self.slideBg.hide()
 | |
|         
 | |
|         self.zoom = ZoomLines(self.viewport)
 | |
|         
 | |
|         self.char = AOCharMovie(self.viewport, self)
 | |
|         self.char.done.connect(self.preanimDone)
 | |
|         self.sideChar = AOCharMovie(self.viewport, self)
 | |
|         self.sideChar.hide()
 | |
|         
 | |
|         self.slideLastWit = []
 | |
|         self.slideLastPos = None
 | |
|         self.slideWitness = AOCharMovie(self.viewport, self)
 | |
|         self.slideWitness.showOnPlay = False
 | |
|         self.slideWitness.hide()
 | |
|         self.slideSpeaker = AOCharMovie(self.viewport, self)
 | |
|         self.slideSpeaker.hide()
 | |
|         self.slideSpeaker.showOnPlay = False
 | |
|         
 | |
|         self.slideOverlay = QtGui.QLabel(self.viewport)
 | |
|         self.slideOverlay.hide()
 | |
|         
 | |
|         self.bench = QtGui.QLabel(self.viewport)
 | |
| 
 | |
|         self.effectView = AOMovie(self.viewport)
 | |
|         self.effectView.setScaledContents(True)
 | |
| 
 | |
|         self.chatbox = Chatbox(self.viewport)
 | |
|         self.chatbox.setScaledContents(True)
 | |
|         
 | |
|         self.text = QtGui.QTextEdit(self.chatbox)
 | |
|         self.text.setFrameStyle(QtGui.QFrame.NoFrame)
 | |
|         self.text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
 | |
|         self.text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
 | |
|         self.text.setReadOnly(True)
 | |
|         self.text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
 | |
|         self.text.initial = None
 | |
|         
 | |
|         self.ao2text = QtGui.QTextEdit(self.chatbox)
 | |
|         self.ao2text.setFrameStyle(QtGui.QFrame.NoFrame)
 | |
|         self.ao2text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
 | |
|         self.ao2text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
 | |
|         self.ao2text.setReadOnly(True)
 | |
|         self.ao2text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
 | |
|         
 | |
|         self.name = QtGui.QLabel(self.chatbox)
 | |
|         
 | |
|         self.presentedEvidence = QtGui.QLabel(self)
 | |
|         self.presentedEvidence.setScaledContents(True)
 | |
|         self.presentedEvidence.hide()
 | |
|         
 | |
|         self.wtceView = WTCEView(self)
 | |
|         self.wtceSignal.connect(self.wtceView.showWTCE)
 | |
| 
 | |
|         self.objectionView = AOMovie(self.viewport)
 | |
|         self.objectionView.setScaledContents(True)
 | |
|         self.objectionView.done.connect(self.objectionDone)
 | |
| 
 | |
|         self.whiteFlashLabel = QtGui.QLabel(self.viewport)
 | |
|         self.whiteFlashLabel.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/realizationflash.png'))
 | |
|         self.whiteFlashLabel.setScaledContents(True)
 | |
|         self.whiteFlashLabel.hide()
 | |
|         self.whiteFlash = QtCore.QTimer()
 | |
|         self.whiteFlash.setSingleShot(False)
 | |
|         self.whiteFlash.timeout.connect(partial(self.setWhiteFlash, False))
 | |
| 
 | |
|         self.screenshake = QtCore.QTimer()
 | |
|         self.screenshake.timeout.connect(self.screenShakeTick)
 | |
|         self.shakesRemaining = 0
 | |
| 
 | |
|         self.onscreenTimerLabels = []
 | |
|         self.onscreenTimerTimes = [0, 0, 0, 0, 0]
 | |
|         self.onscreenTimerPaused = [True, True, True, True, True]
 | |
|         self.onscreenTimer = QtCore.QTimer(self)
 | |
|         self.onscreenTimer.timeout.connect(self.updateOnscreenTimers)
 | |
|         self.onscreenTimerTick = 1000
 | |
|         
 | |
|         for i in range(len(self.onscreenTimerTimes)):
 | |
|             label = QtGui.QLabel(self.viewport)
 | |
|             label.hide()
 | |
|             label.setText("00:00:00")
 | |
|             self.onscreenTimerLabels.append(label)
 | |
|         
 | |
|         self.onscreenTimerLabels[0].setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignTop)
 | |
|         self.onscreenTimerLabels[3].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
 | |
|         self.onscreenTimerLabels[4].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
 | |
|         
 | |
|         # GUI start
 | |
|         self.gameTabs = QtGui.QTabWidget(self)
 | |
|         self.serverTabs = QtGui.QTabWidget(self)
 | |
|         self.tabLog = QtGui.QWidget() # the IC chat log
 | |
|         self.tabEvidence = QtGui.QWidget() # court record
 | |
|         self.tabQueue = QtGui.QWidget() # IC messages pending to be sent
 | |
|         self.tabIniSwap = QtGui.QWidget() # self explanatory
 | |
|         self.tabMute = QtGui.QWidget() # mute a player
 | |
|         self.tabPair = QtGui.QWidget() # AO2 pair
 | |
|         self.tabMisc = QtGui.QWidget() # ao2xp misc/fun stuff
 | |
|         self.tabPlayers = QtGui.QWidget() # player list
 | |
|         self.tabMusic = QtGui.QWidget() # music list
 | |
|         self.tabBackgrounds = QtGui.QWidget() # backgrounds list
 | |
|         
 | |
|         # OOC chat log
 | |
|         self.OOCLog = ChatLogs(self, 1)
 | |
|         self.OOCLog.setReadOnly(True)
 | |
|         self.OOCLog.textChanged.connect(self.onOOCLogChanged)
 | |
|         self.OOCLog.setObjectName("ui_ooc_chatlog")
 | |
|         self.OOCNameInput = QtGui.QLineEdit(self)
 | |
|         self.OOCNameInput.setPlaceholderText('Enter a name...')
 | |
|         self.OOCNameInput.setObjectName("ui_ooc_chat_message")
 | |
|         self.OOCInput = QtGui.QLineEdit(self)
 | |
|         self.OOCInput.setPlaceholderText('Server chat/OOC chat...')
 | |
|         self.OOCInput.returnPressed.connect(self.onOOCReturn)
 | |
|         self.OOCInput.setObjectName("ui_ooc_chat_message")
 | |
|         self.OOCLogin = QtGui.QPushButton("Lo&gin", self)
 | |
|         self.OOCLogin.clicked.connect(self.onOOCLoginClicked)
 | |
|         
 | |
|         # IC chat log
 | |
|         self.ICLog = ChatLogs(self.tabLog, 0, self.OOCLog.logfile)
 | |
|         self.ICLog.setReadOnly(True)
 | |
|         self.ICLog.textChanged.connect(self.onICLogChanged)
 | |
|         self.ICLog.setObjectName("ui_ic_chatlog")
 | |
|         
 | |
|         # Evidence
 | |
|         self.boxEvidence = QtGui.QComboBox(self.tabEvidence)
 | |
|         self.boxEvidence.currentIndexChanged.connect(self.changeGlobalEvidence)
 | |
|         self.boxEvidence.setEditable(1)
 | |
|         self.boxPrivateEvidence = QtGui.QComboBox(self.tabEvidence)
 | |
|         self.boxPrivateEvidence.currentIndexChanged.connect(self.changePrivateEvidence)
 | |
|         self.evidenceDescription = QtGui.QTextEdit(self.tabEvidence)
 | |
|         self.evidenceDescription.setReadOnly(True)
 | |
|         self.evidenceImage = QtGui.QLabel(self.tabEvidence)
 | |
|         self.evidenceImage.setPixmap(QtGui.QPixmap(AOpath + 'evidence/empty.png'))
 | |
|         self.evidenceImage.show()
 | |
|         self.btnEvidenceAdd = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "add.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceAdd.setToolTip('Add new evidence')
 | |
|         self.btnEvidenceAdd.clicked.connect(self.onAddEvidence)
 | |
|         self.btnEvidenceEdit = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "edit.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceEdit.setToolTip('Edit selected evidence')
 | |
|         self.btnEvidenceEdit.clicked.connect(self.onEditEvidence)
 | |
|         self.btnEvidenceDelete = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "delete.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceDelete.setToolTip('Delete selected evidence')
 | |
|         self.btnEvidenceDelete.clicked.connect(self.onDeleteEvidence)
 | |
|         self.btnEvidenceLoad = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "folder.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceLoad.setToolTip('Import all evidence from a file')
 | |
|         self.btnEvidenceLoad.clicked.connect(self.onImportEvidence)
 | |
|         self.btnEvidenceSave = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "disk.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceSave.setToolTip('Export all evidence to a file')
 | |
|         self.btnEvidenceSave.clicked.connect(self.onExportEvidence)
 | |
|         self.btnEvidenceMoveToPrivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceMoveToPrivate.setToolTip('Transfer selected evidence to the private inventory')
 | |
|         self.btnEvidenceMoveToPrivate.clicked.connect(self.onTransferEvidence)
 | |
|         self.btnEvidenceMoveAllToPrivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right2.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceMoveAllToPrivate.setToolTip('Transfer all evidence to the private inventory')
 | |
|         self.btnEvidenceMoveAllToPrivate.clicked.connect(self.onTransferAllEvidence)
 | |
|         self.btnEvidenceMoveToGlobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceMoveToGlobal.setToolTip('Transfer selected evidence to the global inventory')
 | |
|         self.btnEvidenceMoveToGlobal.clicked.connect(self.onTransferEvidence)
 | |
|         self.btnEvidenceMoveAllToGlobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left2.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceMoveAllToGlobal.setToolTip('Transfer all evidence to the global inventory')
 | |
|         self.btnEvidenceMoveAllToGlobal.clicked.connect(self.onTransferAllEvidence)
 | |
|         self.btnEvidenceSwitchToPrivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "world.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceSwitchToPrivate.setToolTip('Switch to the private inventory')
 | |
|         self.btnEvidenceSwitchToPrivate.clicked.connect(self.onSwitchInventory)
 | |
|         self.btnEvidenceSwitchToGlobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "briefcase.png"), "", self.tabEvidence)
 | |
|         self.btnEvidenceSwitchToGlobal.setToolTip('Switch to the global inventory')
 | |
|         self.btnEvidenceSwitchToGlobal.clicked.connect(self.onSwitchInventory)
 | |
|         self.btnEvidencePresent = buttons.PresentButton(self, self.tabEvidence)
 | |
|         self.boxPrivateEvidence.hide()
 | |
|         self.btnEvidenceMoveToGlobal.hide()
 | |
|         self.btnEvidenceMoveAllToGlobal.hide()
 | |
|         self.btnEvidenceSwitchToGlobal.hide()
 | |
|         
 | |
|         # Muting
 | |
|         self.unmutedList = QtGui.QListWidget(self.tabMute)
 | |
|         self.unmutedList.itemClicked.connect(self.changeUnmuteIndex)
 | |
|         self.mutedList = QtGui.QListWidget(self.tabMute)
 | |
|         self.mutedList.itemClicked.connect(self.changeMuteIndex)
 | |
|         self.btnMute = QtGui.QPushButton(self.tabMute)
 | |
|         self.btnMute.setText('>>')
 | |
|         self.btnMute.clicked.connect(self.onMuteClicked)
 | |
|         self.btnUnmute = QtGui.QPushButton(self.tabMute)
 | |
|         self.btnUnmute.setText('<<')
 | |
|         self.btnUnmute.clicked.connect(self.onUnmuteClicked)
 | |
|         self.lblNotMuted = QtGui.QLabel(self.tabMute)
 | |
|         self.lblNotMuted.setText('Not muted')
 | |
|         self.lblMuted = QtGui.QLabel(self.tabMute)
 | |
|         self.lblMuted.setText('Muted')
 | |
|         
 | |
|         # Ini swaps
 | |
|         self.iniSwapList = QtGui.QComboBox(self.tabIniSwap)
 | |
|         self.iniSwapList.currentIndexChanged.connect(self.iniSwapIndexChange)
 | |
|         self.iniSwapList.setEditable(1)
 | |
|         self.btnIniSwapConfirm = QtGui.QPushButton(self.tabIniSwap)
 | |
|         self.btnIniSwapConfirm.setText('Swap')
 | |
|         self.btnIniSwapConfirm.clicked.connect(self.onIniSwapConfirmClicked)
 | |
|         self.btnIniSwapReset = QtGui.QPushButton(self.tabIniSwap)
 | |
|         self.btnIniSwapReset.setText('Reset')
 | |
|         self.btnIniSwapReset.clicked.connect(self.resetIniSwap)
 | |
|         self.btnIniSwapRefresh = QtGui.QPushButton(self.tabIniSwap)
 | |
|         self.btnIniSwapRefresh.setText('Refresh characters')
 | |
|         self.btnIniSwapRefresh.clicked.connect(self.loadSwapCharacters)
 | |
|         self.lblIniSwapInfo = QtGui.QLabel(self.tabIniSwap)
 | |
|         self.lblIniSwapInfo.setText('Not swapped')
 | |
|         
 | |
|         # Pairing
 | |
|         self.cbPair = QtGui.QCheckBox(self.tabPair)
 | |
|         self.cbPair.setChecked(False)
 | |
|         self.boxPair = QtGui.QComboBox(self.tabPair)
 | |
|         self.boxPair.setEditable(True)
 | |
|         self.sliPairOffset = QtGui.QSlider(QtCore.Qt.Horizontal, self.tabPair)
 | |
|         self.sliPairOffset.setRange(-100, 100)
 | |
|         self.sliPairOffset.setValue(0)
 | |
|         self.lblPairOffset = QtGui.QLabel("X offset", self.tabPair)
 | |
|         self.sliPairOffsetY = QtGui.QSlider(QtCore.Qt.Vertical, self.tabPair)
 | |
|         self.sliPairOffsetY.setRange(-100, 100)
 | |
|         self.sliPairOffsetY.setValue(0)
 | |
|         self.lblPairOffsetY = QtGui.QLabel("Y offset", self.tabPair)
 | |
|         self.btnPairOffsetReset = QtGui.QPushButton("Reset", self.tabPair)
 | |
|         self.btnPairOffsetReset.clicked.connect(self.resetPairOffsets)
 | |
|         self.boxPairOrder = QtGui.QComboBox(self.tabPair)
 | |
|         self.boxPairOrder.addItem("Front")
 | |
|         self.boxPairOrder.addItem("Behind")
 | |
|         self.lblPairOrder = QtGui.QLabel("Pairing order", self.tabPair)
 | |
|         
 | |
|         # Misc
 | |
|         self.layMisc = QtGui.QVBoxLayout(self.tabMisc)
 | |
|         self.layMisc.setAlignment(QtCore.Qt.AlignTop)
 | |
|         self.cbMockText = QtGui.QCheckBox()
 | |
|         self.cbMockText.setChecked(False)
 | |
|         self.cbMockText.setText(mockString("mock text"))
 | |
|         self.cbSpacing = QtGui.QCheckBox()
 | |
|         self.cbSpacing.setChecked(False)
 | |
|         self.cbSpacing.setText("S p a c i n g")
 | |
|         self.cbAutoCaps = QtGui.QCheckBox()
 | |
|         self.cbAutoCaps.setChecked(False)
 | |
|         self.cbAutoCaps.setText("Automatic caps and period")
 | |
|         self.cbFirstPerson = QtGui.QCheckBox()
 | |
|         self.cbFirstPerson.setChecked(False)
 | |
|         self.cbFirstPerson.setText("First person view")
 | |
|         self.cbFirstPerson.setToolTip('Sends your message without displaying your character')
 | |
|         self.layMisc.addWidget(self.cbMockText)
 | |
|         self.layMisc.addWidget(self.cbSpacing)
 | |
|         self.layMisc.addWidget(self.cbAutoCaps)
 | |
|         self.layMisc.addWidget(self.cbFirstPerson)
 | |
|         
 | |
|         # Message queue
 | |
|         self.queueItems = QtGui.QListWidget(self.tabQueue)
 | |
|         self.queueItems.itemClicked.connect(self.onMessageQueueItemClicked)
 | |
|         self.btnQueueRemove = QtGui.QPushButton(self.tabQueue)
 | |
|         self.btnQueueRemove.setText('Delete')
 | |
|         self.btnQueueRemove.clicked.connect(self.onRemoveQueueClicked)
 | |
|         self.btnQueueClear = QtGui.QPushButton(self.tabQueue)
 | |
|         self.btnQueueClear.setText('Clear')
 | |
|         self.btnQueueClear.clicked.connect(self.onClearQueueClicked)
 | |
| 
 | |
|         self.gameTabs.addTab(self.tabLog, '&Log')
 | |
|         self.gameTabs.addTab(self.tabEvidence, '&Evidence')
 | |
|         self.gameTabs.addTab(self.tabMute, 'Mu&te')
 | |
|         self.gameTabs.addTab(self.tabIniSwap, '&INI swap')
 | |
|         self.gameTabs.addTab(self.tabPair, 'Pai&r')
 | |
|         self.gameTabs.addTab(self.tabMisc, 'E&xtras')
 | |
|         self.gameTabs.addTab(self.tabQueue, '&Queue')
 | |
|         
 | |
|         # Music list
 | |
|         self.musicItems = QtGui.QListWidget(self.tabMusic)
 | |
|         self.musicItems.itemClicked.connect(self.onMusicItemClicked)
 | |
|         self.musicItems.itemDoubleClicked.connect(self.onMusicItemDoubleClicked)
 | |
|         self.musicSearch = QtGui.QLineEdit(self.tabMusic)
 | |
|         self.musicSearch.setPlaceholderText("Search...")
 | |
|         self.musicSearch.textChanged.connect(self.onMusicSearch)
 | |
|         self.musicSearch.setObjectName("ui_music_search")
 | |
|         self.foundSongItemColor = "background: #80FF80;"
 | |
|         self.btnMusicOptions = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "cog.png"), "", self.tabMusic)
 | |
|         self.btnMusicOptions.setToolTip('Music options')
 | |
|         self.btnMusicOptions.clicked.connect(self.onMusicOptionsClicked)
 | |
|         self.actMusicRandom = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "control_play_blue.png"), "&Play random", self.tabMusic)
 | |
|         self.actMusicRandom.triggered.connect(self.onActMusicRandomTriggered)
 | |
|         self.actMusicCopy = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "page_copy.png"), "&Copy selected song name", self.tabMusic)
 | |
|         self.actMusicCopy.triggered.connect(self.onActMusicCopyTriggered)
 | |
|         self.actMusicCopy.setDisabled(True)
 | |
|         self.actMusicAddCurrent = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "add.png"), "Add current song to private list", self.tabMusic)
 | |
|         self.actMusicAddCurrent.triggered.connect(self.onActMusicAddCurrentTriggered)
 | |
|         self.actMusicAddCurrent.setDisabled(True)
 | |
|         self.actMusicSeparator = QtGui.QAction(self.tabMusic)
 | |
|         self.actMusicSeparator.setSeparator(True)
 | |
|         self.actMusicAdd = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "add.png"), "&Add new entry", self.tabMusic)
 | |
|         self.actMusicAdd.triggered.connect(self.onActMusicAddTriggered)
 | |
|         self.actMusicAdd.setVisible(False)
 | |
|         self.actMusicEdit = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "edit.png"), "&Edit selected entry", self.tabMusic)
 | |
|         self.actMusicEdit.triggered.connect(self.onActMusicEditTriggered)
 | |
|         self.actMusicEdit.setVisible(False)
 | |
|         self.actMusicEdit.setDisabled(True)
 | |
|         self.actMusicDelete = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "delete.png"), "&Delete selected entry", self.tabMusic)
 | |
|         self.actMusicDelete.triggered.connect(self.onActMusicDeleteTriggered)
 | |
|         self.actMusicDelete.setVisible(False)
 | |
|         self.actMusicDelete.setDisabled(True)
 | |
|         self.actMusicEditExternal = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "script_edit.png"), "Edit list in e&xternal editor", self.tabMusic)
 | |
|         self.actMusicEditExternal.triggered.connect(self.onActMusicEditExternalTriggered)
 | |
|         self.actMusicEditExternal.setVisible(False)
 | |
|         self.actMusicRefresh = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_refresh.png"), "&Refresh list", self.tabMusic)
 | |
|         self.actMusicRefresh.triggered.connect(self.onActMusicRefreshTriggered)
 | |
|         self.actMusicRefresh.setVisible(False)
 | |
|         self.actMusicSwitchToGlobal = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "world.png"), "&View global music list", self.tabMusic)
 | |
|         self.actMusicSwitchToGlobal.triggered.connect(self.onActMusicSwitchTriggered)
 | |
|         self.actMusicSwitchToGlobal.setVisible(False)
 | |
|         self.actMusicSwitchToPrivate = QtGui.QAction(QtGui.QIcon(AO2XPpath + "icons/" + "briefcase.png"), "&View private music list", self.tabMusic)
 | |
|         self.actMusicSwitchToPrivate.triggered.connect(self.onActMusicSwitchTriggered)
 | |
|         self.mnuMusicOptions = QtGui.QMenu(self.tabMusic)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicRandom)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicCopy)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicAddCurrent)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicSeparator)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicAdd)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicEdit)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicDelete)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicEditExternal)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicRefresh)
 | |
|         self.mnuMusicOptions.addSeparator()
 | |
|         self.mnuMusicOptions.addAction(self.actMusicSwitchToPrivate)
 | |
|         self.mnuMusicOptions.addAction(self.actMusicSwitchToGlobal)
 | |
| 
 | |
|         self.musicListPrivate = OrderedDict([])
 | |
|         self.onActMusicRefreshTriggered(True)
 | |
|         
 | |
|         # Areas list
 | |
|         self.areaItems = QtGui.QListWidget()
 | |
|         self.areaItems.itemDoubleClicked.connect(self.onAreaItemClicked)
 | |
|         
 | |
|         # Player list
 | |
|         self.playerItems = QtGui.QListWidget(self.tabPlayers)
 | |
|         self.playerItems.itemClicked.connect(self.onPlayerItemClicked)
 | |
|         self.playerItems.setObjectName("ui_player_list")
 | |
|         self.btnPlayerPair = QtGui.QPushButton(self.tabPlayers)
 | |
|         self.btnPlayerPair.setText('Pair')
 | |
|         self.btnPlayerPair.clicked.connect(self.onPlayerPairClicked)
 | |
|         self.btnPlayerKick = QtGui.QPushButton(self.tabPlayers)
 | |
|         self.btnPlayerKick.setText('Kick')
 | |
|         self.btnPlayerKick.clicked.connect(self.onPlayerKickClicked)
 | |
|         self.btnPlayerKick.setDisabled(True)
 | |
|         self.btnPlayerBan = QtGui.QPushButton(self.tabPlayers)
 | |
|         self.btnPlayerBan.setText('Ban')
 | |
|         self.btnPlayerBan.clicked.connect(self.onPlayerBanClicked)
 | |
|         self.btnPlayerBan.setDisabled(True)
 | |
|         
 | |
|         # Background list
 | |
|         self.backgrounds = []
 | |
|         self.backgroundItems = QtGui.QListWidget(self.tabBackgrounds)
 | |
|         self.backgroundItems.itemDoubleClicked.connect(self.onBackgroundItemClicked)
 | |
|         self.backgroundSearch = QtGui.QLineEdit(self.tabBackgrounds)
 | |
|         self.backgroundSearch.setPlaceholderText("Search...")
 | |
|         self.backgroundSearch.textChanged.connect(self.onBackgroundSearch)
 | |
|         self.btnBackgroundsRefresh = QtGui.QPushButton(self.tabBackgrounds)
 | |
|         self.btnBackgroundsRefresh.setText('Refresh')
 | |
|         self.btnBackgroundsRefresh.clicked.connect(self.loadBackgrounds)
 | |
|         self.loadBackgrounds()
 | |
|         
 | |
|         # Demo list
 | |
|         self.demoItems = demo.get_demo_treeview()
 | |
|         self.demoItems.doubleClicked.connect(self.onDemoClicked)
 | |
|         
 | |
|         self.serverTabs.addTab(self.tabMusic, "&Music")
 | |
|         self.serverTabs.addTab(self.areaItems, "&Areas")
 | |
|         self.serverTabs.addTab(self.tabPlayers, 'Pla&yers')
 | |
|         self.serverTabs.addTab(self.tabBackgrounds, "&Backs")
 | |
|         self.serverTabs.addTab(self.demoItems, "Demos")
 | |
|         
 | |
|         # IC options
 | |
|         self.ICChatInput = QtGui.QLineEdit(self)
 | |
|         self.ICChatInput.returnPressed.connect(self.onICReturn)
 | |
|         self.ICChatInput.setPlaceholderText('Game chat')
 | |
|         
 | |
|         self.showname = ""
 | |
|         self.shownameEdit = QtGui.QLineEdit(self)
 | |
|         self.shownameEdit.textChanged.connect(self.onShownameChanged)
 | |
|         self.shownameEdit.setPlaceholderText("Showname")
 | |
|         self.shownameEdit.setToolTip('Set a custom name for your character')
 | |
|         self.shownameEdit.setObjectName("ui_ic_chat_name")
 | |
|         
 | |
|         self.btnChangeChar = QtGui.QPushButton(self)
 | |
|         self.btnChangeChar.clicked.connect(self.onChangeCharClicked)
 | |
|         self.btnChangeChar.setObjectName("ui_change_character")
 | |
|         
 | |
|         self.btnCallMod = QtGui.QPushButton(self)
 | |
|         self.btnCallMod.setText('Call mod')
 | |
|         self.btnCallMod.clicked.connect(self.onCallModClicked)
 | |
|         self.btnCallMod.setObjectName("ui_call_mod")
 | |
|         
 | |
|         self.btnReloadTheme = QtGui.QPushButton(self)
 | |
|         self.btnReloadTheme.setText('Reload theme')
 | |
|         self.btnReloadTheme.clicked.connect(self.onReloadThemeClicked)
 | |
|         self.btnReloadTheme.setVisible(False)
 | |
|         self.btnReloadTheme.setObjectName("ui_reload_theme")
 | |
|         
 | |
|         self.btnSettings = QtGui.QPushButton("&Settings", self)
 | |
|         self.btnSettings.clicked.connect(self.gamewindow.showSettings)
 | |
|         self.btnSettings.setObjectName("ui_settings")
 | |
|         
 | |
|         self.boxEmotes = QtGui.QComboBox(self)
 | |
|         self.boxEmotes.currentIndexChanged.connect(partial(self.changeEmote, True))
 | |
|         self.boxEmotes.setToolTip('Select an emotion for your character')
 | |
|         self.boxEmotes.setObjectName('ui_emote_dropdown')
 | |
|         
 | |
|         self.boxColors = QtGui.QComboBox(self)
 | |
|         self.boxColors.currentIndexChanged.connect(self.setChatColor)
 | |
|         self.boxColors.setToolTip('Change the color of your message')
 | |
|         self.boxColors.setObjectName('ui_text_color')
 | |
|         
 | |
|         self.defaultPositions = ["def", "pro", "wit", "hld", "hlp", "jud", "jur", "sea"]
 | |
|         self.boxPositions = QtGui.QComboBox(self)
 | |
|         self.boxPositions.addItems(self.defaultPositions)
 | |
|         self.boxPositions.currentIndexChanged.connect(self.setPosition)
 | |
|         self.boxPositions.setToolTip('Select your position in the courtroom')
 | |
|         self.boxPositions.setObjectName('ui_pos_dropdown')
 | |
| 
 | |
|         self.boxEffects = QtGui.QComboBox(self)
 | |
|         self.boxEffects.currentIndexChanged.connect(self.ICChatFocus)
 | |
|         self.boxEffects.setToolTip('Show this effect on your next message')
 | |
|         self.boxEffects.setObjectName('ui_effects_dropdown')
 | |
|         
 | |
|         self.boxSounds = QtGui.QComboBox(self)
 | |
|         self.boxSounds.currentIndexChanged.connect(self.ICChatFocus)
 | |
|         self.boxSounds.setToolTip('Play this sound effect')
 | |
|         self.boxSounds.setObjectName('ui_sfx_dropdown')
 | |
|         self.populateSoundList()
 | |
|         
 | |
|         self.cbFlip = QtGui.QCheckBox(self)
 | |
|         self.cbFlip.stateChanged.connect(self.changeFlipCheck)
 | |
|         self.cbFlip.setText('&Flip')
 | |
|         self.cbFlip.resize(self.cbFlip.sizeHint())
 | |
|         self.cbFlip.setToolTip("Mirror your character horizontally")
 | |
|         self.cbFlip.setObjectName('ui_flip')
 | |
|         
 | |
|         self.cbPreanim = QtGui.QCheckBox(self)
 | |
|         self.cbPreanim.setChecked(True)
 | |
|         self.cbPreanim.stateChanged.connect(self.changePreanimCheck)
 | |
|         self.cbPreanim.setText('&Pre-anim')
 | |
|         self.cbPreanim.setToolTip("Play a character-specific animation before the next message")
 | |
|         self.cbPreanim.setObjectName('ui_pre')
 | |
| 
 | |
|         self.cbBench = QtGui.QCheckBox(self)
 | |
|         self.cbBench.setChecked(True)
 | |
|         self.cbBench.setText('&Desk')
 | |
|         self.cbBench.stateChanged.connect(self.ICChatFocus)
 | |
|         self.cbBench.setToolTip('Show or hide the desk in front of your character')
 | |
|                 
 | |
|         self.cbSlide = QtGui.QCheckBox(self)
 | |
|         self.cbSlide.stateChanged.connect(self.ICChatFocus)
 | |
|         self.cbSlide.setText('Slide')
 | |
|         self.cbSlide.resize(self.cbSlide.sizeHint())
 | |
|         self.cbSlide.setToolTip("Tell clients to play courtroom slide animations for your message")
 | |
|         
 | |
|         self.cbNoInterrupt = QtGui.QCheckBox(self)
 | |
|         self.cbNoInterrupt.setChecked(False)
 | |
|         self.cbNoInterrupt.stateChanged.connect(self.ICChatFocus)
 | |
|         self.cbNoInterrupt.setText('&No interrupt')
 | |
|         self.cbNoInterrupt.setToolTip("Show the next message immediately, ignoring animations")
 | |
|         self.cbNoInterrupt.setObjectName('ui_immediate')
 | |
| 
 | |
|         self.cbAdditive = QtGui.QCheckBox(self)
 | |
|         self.cbAdditive.setChecked(False)
 | |
|         self.cbAdditive.setText('Additi&ve')
 | |
|         self.cbAdditive.resize(self.cbAdditive.sizeHint())
 | |
|         self.cbAdditive.clicked.connect(self.ICChatFocus)
 | |
|         self.cbAdditive.setToolTip('Append the next message to the previous one, without a new textbox')
 | |
|         self.cbAdditive.setObjectName('ui_additive')
 | |
|         
 | |
|         # Emotions
 | |
|         self.btnPrevEmotePage = buttons.BackEmoteButton(self)
 | |
|         self.btnPrevEmotePage.hide()
 | |
|         self.btnPrevEmotePage.setObjectName("ui_emote_left")
 | |
|         self.btnNextEmotePage = buttons.NextEmoteButton(self)
 | |
|         self.btnNextEmotePage.show()
 | |
|         self.btnNextEmotePage.setObjectName("ui_emote_right")
 | |
|         self.currentEmotePage = 0
 | |
|         self.maxEmotesOnPage = 0
 | |
|         self.emoteButtons = []
 | |
|         
 | |
|         # Special effects
 | |
|         self.btnRealization = buttons.AOToggleButton(self, "realization")
 | |
|         self.btnRealization.clicked.connect(self.onRealizationClicked)
 | |
|         self.btnRealization.setToolTip('Show the next message with a realization effect')
 | |
|         self.btnRealization.setObjectName("ui_realization")
 | |
|         
 | |
|         self.btnShake = buttons.AOToggleButton(self, "screenshake") # AO 2.8
 | |
|         self.btnShake.clicked.connect(self.onShakeClicked)
 | |
|         self.btnShake.setToolTip('Show the next message with a shaking effect')
 | |
|         self.btnShake.setObjectName("ui_screenshake")
 | |
|         
 | |
|         self.sndRealization = audio.loadHandle(False, AOpath + 'sounds/general/sfx-realization.wav', 0, 0, 0)
 | |
|         #self.sndShake = audio.loadHandle(False, AOpath + 'sounds/general/sfx-damage.wav', 0, 0, 0)
 | |
|         
 | |
|         # Objections
 | |
|         self.btnCustomObjection = buttons.CustomObjection(self)
 | |
|         self.btnCustomObjection.clicked.connect(self.ICChatFocus)
 | |
|         self.btnCustomObjection.setToolTip("Custom objection")
 | |
|         self.btnCustomObjection.setObjectName("ui_custom_objection")
 | |
|         self.btnTakeThat = buttons.Objections(self, 3)
 | |
|         self.btnTakeThat.clicked.connect(self.ICChatFocus)
 | |
|         self.btnTakeThat.setToolTip("Take that!")
 | |
|         self.btnTakeThat.setObjectName("ui_take_that")
 | |
|         self.btnObjection = buttons.Objections(self, 2)
 | |
|         self.btnObjection.clicked.connect(self.ICChatFocus)
 | |
|         self.btnObjection.setToolTip("Objection!")
 | |
|         self.btnObjection.setObjectName("ui_objection")
 | |
|         self.btnHoldIt = buttons.Objections(self, 1)
 | |
|         self.btnHoldIt.clicked.connect(self.ICChatFocus)
 | |
|         self.btnHoldIt.setToolTip("Hold it!")
 | |
|         self.btnHoldIt.setObjectName("ui_hold_it")
 | |
|         self.sndObjection = 0
 | |
|         
 | |
|         # Judge buttons
 | |
|         self.btnDefenseBar = buttons.PenaltyBars(self, 1)
 | |
|         self.btnDefenseBar.minusClicked.connect(self.onPenaltyBarMinusClicked)
 | |
|         self.btnDefenseBar.plusClicked.connect(self.onPenaltyBarPlusClicked)
 | |
|         self.btnDefenseBar.btnMinus.setObjectName("ui_defense_minus")
 | |
|         self.btnDefenseBar.btnPlus.setObjectName("ui_defense_plus")
 | |
|         self.btnProsecutionBar = buttons.PenaltyBars(self, 2)
 | |
|         self.btnProsecutionBar.minusClicked.connect(self.onPenaltyBarMinusClicked)
 | |
|         self.btnProsecutionBar.plusClicked.connect(self.onPenaltyBarPlusClicked)
 | |
|         self.btnProsecutionBar.btnMinus.setObjectName("ui_prosecution_minus")
 | |
|         self.btnProsecutionBar.btnPlus.setObjectName("ui_prosecution_plus")
 | |
|         self.btnWitnessTestimony = buttons.WTCEbuttons(self, 0)
 | |
|         self.btnWitnessTestimony.clicked.connect(self.OnWTCEButtonClicked)
 | |
|         self.btnWitnessTestimony.setObjectName("ui_witness_testimony")
 | |
|         self.btnCrossExamination = buttons.WTCEbuttons(self, 1)
 | |
|         self.btnCrossExamination.clicked.connect(self.OnWTCEButtonClicked)
 | |
|         self.btnCrossExamination.setObjectName("ui_cross_examination")
 | |
|         self.btnNotGuilty = buttons.WTCEbuttons(self, 2, 0)
 | |
|         self.btnNotGuilty.clicked.connect(self.OnWTCEButtonClicked)
 | |
|         self.btnNotGuilty.setObjectName("ui_not_guitly")
 | |
|         self.btnGuilty = buttons.WTCEbuttons(self, 2, 1)
 | |
|         self.btnGuilty.clicked.connect(self.OnWTCEButtonClicked)
 | |
|         self.btnGuilty.setObjectName("ui_guilty")
 | |
|         self.btnWitnessTestimony.show()
 | |
|         self.btnCrossExamination.show()
 | |
|         self.btnNotGuilty.show()
 | |
|         self.btnGuilty.show()
 | |
|         self.presenting = -1
 | |
|         
 | |
|         # Volume sliders and their labels
 | |
|         self.lblMusicVolume = QtGui.QLabel("Music", self)
 | |
|         self.lblSoundVolume = QtGui.QLabel("SFX", self)
 | |
|         self.lblBlipsVolume = QtGui.QLabel("Blips", self)
 | |
|         self.lblPing = QtGui.QLabel(self)
 | |
|         self.sliMusicVolume = QtGui.QSlider(QtCore.Qt.Horizontal, self)
 | |
|         self.sliSoundVolume = QtGui.QSlider(QtCore.Qt.Horizontal, self)
 | |
|         self.sliBlipsVolume = QtGui.QSlider(QtCore.Qt.Horizontal, self)
 | |
|         self.sliMusicVolume.setRange(0, 100)
 | |
|         self.sliSoundVolume.setRange(0, 100)
 | |
|         self.sliBlipsVolume.setRange(0, 100)
 | |
|         self.sliMusicVolume.valueChanged.connect(self.changeMusicVolume)
 | |
|         self.sliSoundVolume.valueChanged.connect(self.changeSoundVolume)
 | |
|         self.sliBlipsVolume.valueChanged.connect(self.changeBlipVolume)
 | |
|         self.sliMusicVolume.setObjectName("ui_music_slider")
 | |
|         self.sliSoundVolume.setObjectName("ui_sfx_slider")
 | |
|         self.sliBlipsVolume.setObjectName("ui_blip_slider")
 | |
|         self.lblMusicVolume.setObjectName("ui_music_label")
 | |
|         self.lblSoundVolume.setObjectName("ui_sfx_label")
 | |
|         self.lblBlipsVolume.setObjectName("ui_blip_label")
 | |
|         
 | |
|         # Demo playback seekbar
 | |
|         self.sliDemoSeekbar = QtGui.QSlider(QtCore.Qt.Horizontal, self)
 | |
|         self.sliDemoSeekbar.valueChanged.connect(self.demoSeek)
 | |
|         self.sliDemoSeekbar.setVisible(False)
 | |
|         self.sliDemoSeekbar.setMinimum(0)
 | |
|         
 | |
|         self.lblNotMuted.setObjectName("lblNotMuted")
 | |
|         self.lblMuted.setObjectName("lblMuted")
 | |
|         self.lblIniSwapInfo.setObjectName("lblIniSwapInfo")
 | |
|         self.lblPairOffset.setObjectName("lblPairOffset")
 | |
|         self.lblPairOffsetY.setObjectName("lblPairOffsetY")
 | |
|         self.lblPairOrder.setObjectName("lblPairOrder")
 | |
|         self.tabLog.setObjectName("tabLog")
 | |
|         self.tabEvidence.setObjectName("tabEvidence")
 | |
|         self.tabMute.setObjectName("tabMute")
 | |
|         self.tabIniSwap.setObjectName("tabIniSwap")
 | |
|         self.tabPair.setObjectName("tabPair")
 | |
|         self.tabMisc.setObjectName("tabMisc")
 | |
|         self.tabQueue.setObjectName("tabQueue")
 | |
|         self.tabMusic.setObjectName("tabMusic")
 | |
|         self.tabPlayers.setObjectName("tabPlayers")
 | |
|         self.tabBackgrounds.setObjectName("tabBackgrounds")
 | |
|         
 | |
|         # GUI end
 | |
|         
 | |
|         self.name.show()
 | |
|         self.char.show()
 | |
|         self.court.show()
 | |
|         self.bench.show()
 | |
|         self.chatbox.show()
 | |
|         
 | |
|         self.areas = []
 | |
|         self.areasLen = 0
 | |
|         self.noARUP = False
 | |
|         self.muteSelected = -1
 | |
|         self.unmuteSelected = -1
 | |
|         self.muted = []
 | |
|         self.myChar = -1
 | |
|         self.myChatColor = 0
 | |
|         self.charEmotes = []
 | |
|         self.selectedEmote = 0
 | |
|         self.charName = ''
 | |
|         self.charShowname = ''
 | |
|         self.charSide = 'def'
 | |
|         self.lastMessage = ''
 | |
|         self.inboxQueue = []
 | |
|         self.textWaitTime = int(getOption("General", "text stay time", 200))
 | |
|         self.messageQueue = []
 | |
|         self.selectedMessage = -1
 | |
|         self.evidence = []
 | |
|         self.privateEvidence = []
 | |
|         self.selectedEvidence = -1
 | |
|         self.present = False
 | |
|         self.playerList = {}
 | |
|         self.selectedPlayer = -1
 | |
|         self.myFlip = 0
 | |
|         self.playPreanim = 1
 | |
|         self.demoRecorder = None
 | |
|         self.demoPlaying = False
 | |
|         self.musicList = {}
 | |
|         self.pickedMusicItem = False
 | |
|         self.currentMusicURL = None
 | |
|         
 | |
|         self.slideEnabled = getOption("General", "slide", False) == 'True'
 | |
|         self.slideAvailable = False
 | |
|         self.slideHasOverlay = False
 | |
|         self.slideKind = 0 # 0 = def-pro, 1 = def-wit, 2 = pro-wit
 | |
|         self.slideDirection = 0 # 0 = left to right, 1 = right to left
 | |
|         
 | |
|         # slideMap[oldPos][newPos] = [kind, direction]
 | |
|         self.slideMap = {
 | |
|             "def": { "pro": [0, 0], "wit": [1, 0] },
 | |
|             "wit": { "def": [1, 1], "pro": [2, 0] },
 | |
|             "pro": { "def": [0, 1], "wit": [2, 1] },
 | |
|         }
 | |
|         
 | |
|         self.loadSwapCharacters()
 | |
|         self.iniSwapList.setCurrentIndex(0)
 | |
|         self.evidenceEditor = EditEvidenceDialog(self)
 | |
|         
 | |
|         self.connect(self, QtCore.SIGNAL('showMessage(QString, QString, QString)'), self.showMessage)
 | |
|         
 | |
|         self.charSelect = charselect.charselect(self)
 | |
|         
 | |
|         self.wtceSfx = 0
 | |
|         self.guiltySfx = 0
 | |
|         self.notGuiltySfx = 0
 | |
|         
 | |
|         self.stream = 0
 | |
|         self.specialStream = False
 | |
|         self.downloadThread = None
 | |
|         self.tcp = None
 | |
|         self.demoPlayer = None
 | |
|         
 | |
|         # Finally, load the theme
 | |
|         self.width = 820
 | |
|         self.height = 730
 | |
|         self.defaultStyle = QtGui.QApplication.style().objectName()
 | |
|         self.loadTheme()
 | |
|             
 | |
|     def loadTheme(self, switching=False):
 | |
|         theme = getOption("General", "theme", "default")
 | |
|         # try:
 | |
|         stylesheet = ""
 | |
|         self.emotePageGeometry = []
 | |
|         self.viewportScale = 0
 | |
|         self.gamewindow.setStyleSheet("")
 | |
|         self.chatbox.resetGeometry()
 | |
|         self.btnReloadTheme.setVisible(False)
 | |
|         self.cbBench.setVisible(True)
 | |
|         self.cbSlide.setVisible(True)
 | |
|         self.nameFontPointSize = 6
 | |
|         self.textFontPointSize = 12
 | |
|         
 | |
|         for w in [self.gameTabs, self.serverTabs]:
 | |
|             stack = w.findChild(QtGui.QStackedWidget)
 | |
|             if stack:
 | |
|                 stack.setAutoFillBackground(False)
 | |
|                 stack.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
 | |
|         
 | |
|         for btn in [self.btnRealization, self.btnShake,
 | |
|                     self.btnCustomObjection, self.btnObjection,
 | |
|                     self.btnTakeThat, self.btnHoldIt, self.btnGuilty,
 | |
|                     self.btnNotGuilty, self.btnWitnessTestimony,
 | |
|                     self.btnCrossExamination, self.btnDefenseBar,
 | |
|                     self.btnProsecutionBar]:
 | |
|             btn.setPixmaps(theme)
 | |
|             
 | |
|         # Design
 | |
|         courtroomDesign = AO2XPpath + "ao2xp_themes/" + theme + '/courtroom_design.ini'
 | |
|         if exists(courtroomDesign):
 | |
|             design = {}
 | |
|             with open(courtroomDesign) as f:
 | |
|                 for keys in f.read().split("\n"):
 | |
|                     if not keys or "=" not in keys or keys[0] == ";": continue
 | |
| 
 | |
|                     key, value = keys.split("=")
 | |
|                     design[key.strip()] = value.split(',')
 | |
|                     
 | |
|             geometry = {
 | |
|                 "viewport": self.viewport,
 | |
|                 "ic_chatlog": self.gameTabs,
 | |
|                 "server_chatlog": self.OOCLog,
 | |
|                 "ooc_chat_name": self.OOCNameInput,
 | |
|                 "ooc_chat_message": self.OOCInput,
 | |
|                 "music_label": self.lblMusicVolume,
 | |
|                 "sfx_label": self.lblSoundVolume,
 | |
|                 "blip_label": self.lblBlipsVolume,
 | |
|                 "music_slider": self.sliMusicVolume,
 | |
|                 "sfx_slider": self.sliSoundVolume,
 | |
|                 "blip_slider": self.sliBlipsVolume,
 | |
|                 "emote_dropdown": self.boxEmotes,
 | |
|                 "effects_dropdown": self.boxEffects,
 | |
|                 "sfx_dropdown": self.boxSounds,
 | |
|                 "pos_dropdown": self.boxPositions,
 | |
|                 "text_color": self.boxColors,
 | |
|                 "change_character": self.btnChangeChar,
 | |
|                 "call_mod": self.btnCallMod,
 | |
|                 "reload_theme": self.btnReloadTheme,
 | |
|                 "ao2_ic_chat_name": self.shownameEdit,
 | |
|                 "settings": self.btnSettings,
 | |
|                 "ao2_chatbox": self.chatbox,
 | |
|                 "ao2_ic_chat_message": self.ICChatInput,
 | |
|                 "message": self.text,
 | |
|                 "showname": self.name,
 | |
|                 "music_list": self.serverTabs,
 | |
|                 "defense_bar": self.btnDefenseBar,
 | |
|                 "prosecution_bar": self.btnProsecutionBar,
 | |
|             }
 | |
|             
 | |
|             move = {
 | |
|                 "pre": self.cbPreanim,
 | |
|                 "flip": self.cbFlip,
 | |
|                 "additive": self.cbAdditive,
 | |
|                 "slide_enable": self.cbSlide,
 | |
|                 "pre_no_interrupt": self.cbNoInterrupt,
 | |
|                 "hold_it": self.btnHoldIt,
 | |
|                 "objection": self.btnObjection,
 | |
|                 "take_that": self.btnTakeThat,
 | |
|                 "custom_objection": self.btnCustomObjection,
 | |
|                 "emote_left": self.btnPrevEmotePage,
 | |
|                 "emote_right": self.btnNextEmotePage,
 | |
|                 "realization": self.btnRealization,
 | |
|                 "screenshake": self.btnShake,
 | |
|                 "not_guilty": self.btnNotGuilty,
 | |
|                 "guilty": self.btnGuilty,
 | |
|                 "witness_testimony": self.btnWitnessTestimony,
 | |
|                 "cross_examination": self.btnCrossExamination,
 | |
|                 "defense_plus": self.btnDefenseBar.btnPlus,
 | |
|                 "defense_minus": self.btnDefenseBar.btnMinus,
 | |
|                 "prosecution_plus": self.btnProsecutionBar.btnPlus,
 | |
|                 "prosecution_minus": self.btnProsecutionBar.btnMinus,
 | |
|             }
 | |
|             
 | |
|             for e in geometry.keys():
 | |
|                 if e in design:
 | |
|                     geometry[e].setGeometry(*[int(x) for x in design[e]])
 | |
|                 
 | |
|             for e in move.keys():
 | |
|                 if e in design:
 | |
|                     move[e].move(*[int(x) for x in design[e]][0:2])
 | |
|             
 | |
|             if "emotes" in design:
 | |
|                 self.emotePageGeometry = [int(x) for x in design["emotes"]]
 | |
|             else:
 | |
|                 self.emotePageGeometry = [0, 0, 0, 0]
 | |
|                 
 | |
|             if "emote_button_spacing" in design:
 | |
|                 self.emotePageGeometry += [int(x) for x in design["emote_button_spacing"]]
 | |
|             else:
 | |
|                 self.emotePageGeometry += [1, 1]
 | |
|                 
 | |
|             if "found_song_color" in design:
 | |
|                 self.foundSongItemColor = QtGui.QColor(*[int(x) for x in design["found_song_color"]])
 | |
|                 
 | |
|             self.cbSlide.setVisible("slide_enable" in design)
 | |
|             self.cbBench.setVisible("ao2xp_desk" in design)    
 | |
|             self.btnReloadTheme.setVisible(True)
 | |
|                 
 | |
|             QtGui.QApplication.setStyle('plastique')
 | |
|             for w in [self.gameTabs, self.serverTabs]:
 | |
|                 stack = w.findChild(QtGui.QStackedWidget)
 | |
|                 if stack:
 | |
|                     stack.setAutoFillBackground(False)
 | |
|                     stack.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
 | |
|         else:
 | |
|             QtGui.QApplication.setStyle(self.defaultStyle)
 | |
|             for w in [self.gameTabs, self.serverTabs]:
 | |
|                 stack = w.findChild(QtGui.QStackedWidget)
 | |
|                 if stack:
 | |
|                     stack.setAutoFillBackground(True)
 | |
|                     stack.setAttribute(QtCore.Qt.WA_NoSystemBackground, False)
 | |
| 
 | |
|         # pyThemes
 | |
|         pyTheme = AO2XPpath + "ao2xp_themes/" + theme + "/theme.py"
 | |
|         if exists(pyTheme):
 | |
|             with open(pyTheme) as t:
 | |
|                 exec t
 | |
|         else:
 | |
|             self._themeCommon()
 | |
|                 
 | |
|         if switching:
 | |
|             # This is to reset the colors on the music list. Not necessary on startup
 | |
|             self.onMusicSearch("")
 | |
|                 
 | |
|         if not self.viewportScale:
 | |
|             self.viewportScale = self.viewport.height() / float(192)
 | |
|             
 | |
|         self.viewportRatio = self.viewport.width() / float(self.viewport.height())
 | |
|             
 | |
|         self.court.resize(self.viewport.size())
 | |
|         self.bench.resize(self.viewport.size())
 | |
|         self.whiteFlashLabel.resize(self.viewport.size())
 | |
|         self.effectView.resize()
 | |
|         self.objectionView.resize()
 | |
|         self.zoom.resize()
 | |
|         self.wtceView.resize()
 | |
|         self.char.resize()
 | |
|         self.sideChar.resize()
 | |
|         self.slideWitness.resize()
 | |
|         self.slideSpeaker.resize()
 | |
|         self.text.initial = self.text.geometry()
 | |
|         self.ao2text.setGeometry(self.text.initial)
 | |
|         self.ao2text.setStyleSheet(self.text.styleSheet())
 | |
|         self.sliDemoSeekbar.setGeometry(self.ICChatInput.geometry())
 | |
|         
 | |
|         # Theme chatbox
 | |
|         chatboxPixmap = QtGui.QPixmap(testPath(
 | |
|             AO2XPpath + "ao2xp_themes/%s/chatmed.png" % theme,
 | |
|             AO2XPpath + "ao2xp_themes/%s/chat.png" % theme,
 | |
|             AO2XPpath + 'themes/default/chatmed.png'
 | |
|         ))
 | |
|         if not self.chatbox.geometrySet:
 | |
|             self.chatboxWidth = self.viewport.width()
 | |
|             self.chatboxHeight = chatboxPixmap.size().height() * self.viewportScale
 | |
|             self.chatbox.setGeometry(0, self.viewport.height() - self.chatboxHeight, self.chatboxWidth, self.chatboxHeight)
 | |
|         else:
 | |
|             self.chatboxWidth = self.chatbox.width()
 | |
|             self.chatboxHeight = self.chatbox.height()
 | |
|         self.chatbox.setPixmap(chatboxPixmap.scaled(self.chatboxWidth, self.chatboxHeight, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
|         
 | |
|         # Theme background
 | |
|         courtroomBackground = AO2XPpath + "ao2xp_themes/" + theme + '/courtroombackground.png'
 | |
|         if exists(courtroomBackground):
 | |
|             stylesheet += "QTabWidget {background-color: transparent;} QMainWindow { background-image: url(./" + courtroomBackground + ");}"
 | |
|             courtroomBackground = QtGui.QPixmap(courtroomBackground)
 | |
|             self.width = courtroomBackground.size().width()
 | |
|             self.height = courtroomBackground.size().height()
 | |
|         
 | |
|         # Stylesheet
 | |
|         courtroomStylesheets = AO2XPpath + "ao2xp_themes/" + theme + '/courtroom_stylesheets.css'
 | |
|         if exists(courtroomStylesheets):
 | |
|             with open(courtroomStylesheets) as f:
 | |
|                 stylesheet += f.read()
 | |
|             
 | |
|         self.gamewindow.setStyleSheet(stylesheet)
 | |
|  
 | |
|         self.presentedEvidence.setGeometry(self.viewport.x() + 16, self.viewport.y() + 16, 70 * self.viewportScale, 70 * self.viewportScale)
 | |
|         
 | |
|         # Theme fonts
 | |
|         fontDb = QtGui.QFontDatabase()
 | |
|         fonts = {
 | |
|             "showname": {
 | |
|                 "QFont": QtGui.QFont(),
 | |
|                 "pointSize": self.nameFontPointSize,
 | |
|                 "widget": self.name,
 | |
|                 "family": "Ace Name",
 | |
|                 "color": "255, 255, 255",
 | |
|                 "bold": 0,
 | |
|                 "path": AO2XPpath + 'font/Ace_Name_Regular.ttf'
 | |
|                 },
 | |
|             "message": {
 | |
|                 "QFont": QtGui.QFont(),
 | |
|                 "widget": self.text,
 | |
|                 "pointSize": self.textFontPointSize,
 | |
|                 "family": "Igiari Cyrillic",
 | |
|                 "color": "255, 255, 255", # Ignored but included for consistency
 | |
|                 "bold": 0,
 | |
|                 "path": AO2XPpath + 'font/igiari-cyrillic.ttf'
 | |
|                 },
 | |
|         }
 | |
|         
 | |
|         courtroomFonts = AO2XPpath + "ao2xp_themes/" + theme + '/courtroom_fonts.ini'
 | |
|         if exists(courtroomFonts):
 | |
|             fontData = {}
 | |
|             with open(courtroomFonts) as f:
 | |
|                 for keys in f.read().split("\n"):
 | |
|                     if not keys or "=" not in keys or keys[0] == ";": continue
 | |
|                     key, value = keys.split("=")
 | |
|                     fontData[key.strip()] = value.split(',')
 | |
|             
 | |
|             if "showname" in fontData:
 | |
|                 fonts["showname"]["pointSize"] = int(*fontData["showname"])
 | |
|             if "showname_font" in fontData:
 | |
|                 fonts["showname"]["family"] = fontData["showname_font"][0].strip()
 | |
|             if "showname_color" in fontData:
 | |
|                 fonts["showname"]["color"] = ",".join(fontData["showname_color"])
 | |
|             if "showname_bold" in fontData:
 | |
|                 fonts["showname"]["bold"] = int(*fontData["showname_bold"])
 | |
|             if "showname_fontpath" in fontData: # AO2XP exclusive
 | |
|                 fonts["showname"]["path"] = AO2XPpath + "ao2xp_themes/" + theme + "/" + fontData["showname_fontpath"][0].strip()
 | |
|                 
 | |
|             if "message" in fontData:
 | |
|                 fonts["message"]["pointSize"] = int(*fontData["message"])
 | |
|             if "message_font" in fontData:
 | |
|                 fonts["message"]["family"] = fontData["message_font"][0].strip()
 | |
|             if "message_bold" in fontData:
 | |
|                 fonts["message"]["bold"] = int(*fontData["message_bold"])
 | |
|             if "message_fontpath" in fontData: # AO2XP exclusive
 | |
|                 fonts["message"]["path"] = AO2XPpath + "ao2xp_themes/" + theme + "/" + fontData["message_fontpath"][0].strip()
 | |
| 
 | |
|         for w in ["showname", "message"]:
 | |
|             fontDb.addApplicationFont(fonts[w]["path"])
 | |
|             QFont = fonts[w]["QFont"]
 | |
|             QFont.setPointSize(fonts[w]["pointSize"])
 | |
|             QFont.setFamily(fonts[w]["family"])
 | |
|             QFont.setBold(fonts[w]["bold"])
 | |
|             fonts[w]["widget"].setStyleSheet("color: rgb(%s)" % fonts[w]["color"])
 | |
|                 
 | |
|         self.text.setFont(fonts["message"]["QFont"])
 | |
|         self.ao2text.setFont(self.text.font())
 | |
|         self.name.setFont(fonts["showname"]["QFont"])
 | |
|         
 | |
|         for label in self.onscreenTimerLabels:
 | |
|             label.resize(self.viewport.width(), self.viewport.height())
 | |
|             label.setFont(self.name.font())
 | |
|             label.setStyleSheet(self.name.styleSheet())
 | |
|         
 | |
|         # TODO: Figure out proper height
 | |
|         px = fonts["showname"]["pointSize"] * 72 / 96
 | |
|         self.onscreenTimerLabels[2].move(self.onscreenTimerLabels[1].x(), self.onscreenTimerLabels[1].y() + px + 4)
 | |
|         self.onscreenTimerLabels[4].move(self.onscreenTimerLabels[3].x(), self.onscreenTimerLabels[3].y() + px + 4)
 | |
|             
 | |
|         # Load emote buttons
 | |
|         # TODO: Buggy on theme switch / reload
 | |
|         xMod_count = yMod_count = 0
 | |
|         left, top, width, height, hSpacing, vSpacing = self.emotePageGeometry
 | |
|         columns = (width - 40) / (hSpacing + 40) + 1
 | |
|         rows = (height - 40) / (vSpacing + 40) + 1
 | |
|         self.maxEmotesOnPage = columns * rows
 | |
|         
 | |
|         if len(self.emoteButtons) > 0:
 | |
|             for button in self.emoteButtons:
 | |
|                 button.setParent(None)
 | |
|                 button.deleteLater()
 | |
|                 button = None
 | |
|         
 | |
|         self.emoteButtons = []
 | |
|         
 | |
|         for i in range(self.maxEmotesOnPage):
 | |
|             xPos = (40 + hSpacing) * xMod_count
 | |
|             yPos = (40 + vSpacing) * yMod_count
 | |
|             xMod_count += 1
 | |
|             if xMod_count == columns:
 | |
|                 xMod_count = 0
 | |
|                 yMod_count += 1
 | |
|             
 | |
|             button = buttons.EmoteButton(self, i)
 | |
|             button.move(left + xPos, top + yPos)
 | |
|             button.clicked.connect(self.ICChatFocus)
 | |
|             button.show()
 | |
|             button.lower()
 | |
|             self.emoteButtons.append(button)
 | |
|             
 | |
|         self.btnPrevEmotePage.raise_()
 | |
|         self.btnNextEmotePage.raise_()
 | |
|             
 | |
|         if switching:
 | |
|             self.setBackground()
 | |
|             self.setScene()
 | |
|             self.boxEmotes.setCurrentIndex(0)
 | |
|             self.setEmotePage()
 | |
|             self.gamewindow.setFixedSize(self.width, self.height)
 | |
|             self.gamewindow.center()
 | |
|         # except Exception as e:
 | |
|            # QtGui.QMessageBox.critical(None, "Unable to load theme", "There was a problem loading the current theme \"%s\":\n\n%s." % (theme, e))
 | |
|            # os._exit(-2)
 | |
|            
 | |
|     def _themeCommon(self):
 | |
|         # IC input and demo slider
 | |
|         viewportRight = max(self.viewport.x() + self.viewport.width(), 512)
 | |
| 
 | |
|         # IC options
 | |
|         gameTabsHeight = self.gameTabs.height() - self.gameTabs.findChild(QtGui.QTabBar).height()
 | |
|         self.ICLog.setGeometry(0, 0, self.gameTabs.width(), gameTabsHeight)
 | |
|         self.boxPrivateEvidence.setGeometry(8, 8, 192, 20)
 | |
|         self.evidenceDescription.setGeometry(8, 108, self.gameTabs.width() - 22, gameTabsHeight - 110)
 | |
|         self.evidenceImage.setGeometry(self.evidenceDescription.x() + self.evidenceDescription.width() - 70, 8, 70, 70)
 | |
|         self.boxEvidence.setGeometry(8, 8, self.evidenceImage.x() - 16, 20)
 | |
|         self.btnEvidenceAdd.move(8, 32)
 | |
|         self.btnEvidenceAdd.resize(30, 26)
 | |
|         
 | |
|         evidenceadd_size = self.btnEvidenceAdd.size()
 | |
|         self.btnEvidenceEdit.resize(evidenceadd_size)
 | |
|         self.btnEvidenceDelete.resize(evidenceadd_size)
 | |
|         self.btnEvidenceLoad.resize(evidenceadd_size)
 | |
|         self.btnEvidenceSave.resize(evidenceadd_size)
 | |
|         self.btnEvidenceMoveToPrivate.resize(evidenceadd_size)
 | |
|         self.btnEvidenceMoveAllToPrivate.resize(evidenceadd_size)
 | |
|         self.btnEvidenceMoveToGlobal.resize(evidenceadd_size)
 | |
|         self.btnEvidenceMoveAllToGlobal.resize(evidenceadd_size)
 | |
|         self.btnEvidenceSwitchToPrivate.resize(evidenceadd_size)
 | |
|         self.btnEvidenceSwitchToGlobal.resize(evidenceadd_size)
 | |
|         self.btnEvidenceEdit.move(3 + self.btnEvidenceAdd.x() + self.btnEvidenceAdd.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceDelete.move(3 + self.btnEvidenceEdit.x() + self.btnEvidenceEdit.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceMoveToPrivate.move(3 + self.btnEvidenceDelete.x() + self.btnEvidenceDelete.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceMoveAllToPrivate.move(3 + self.btnEvidenceMoveToPrivate.x() + self.btnEvidenceMoveToPrivate.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceMoveToGlobal.move(3 + self.btnEvidenceDelete.x() + self.btnEvidenceDelete.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceMoveAllToGlobal.move(3 + self.btnEvidenceMoveToPrivate.x() + self.btnEvidenceMoveToPrivate.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceSwitchToPrivate.move(3 + self.btnEvidenceMoveAllToPrivate.x() + self.btnEvidenceMoveAllToPrivate.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceSwitchToGlobal.move(3 + self.btnEvidenceMoveAllToPrivate.x() + self.btnEvidenceMoveAllToPrivate.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceLoad.move(3 + self.btnEvidenceSwitchToPrivate.x() + self.btnEvidenceSwitchToPrivate.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidenceSave.move(3 + self.btnEvidenceLoad.x() + self.btnEvidenceLoad.size().width(), self.btnEvidenceAdd.y())
 | |
|         self.btnEvidencePresent.move(self.evidenceDescription.x() + self.evidenceDescription.width() / 2 - self.btnEvidencePresent.button_off.size().width() / 2, self.evidenceDescription.y() - self.btnEvidencePresent.button_off.size().height())
 | |
| 
 | |
|         self.queueItems.setGeometry(8, 8, self.gameTabs.width() - 22, gameTabsHeight - self.btnQueueRemove.sizeHint().height() - 20)
 | |
|         self.btnQueueRemove.resize(self.btnQueueRemove.sizeHint())
 | |
|         self.btnQueueRemove.move(8, self.queueItems.size().height() + 16)
 | |
|         self.btnQueueClear.move(self.btnQueueRemove.x() + self.btnQueueRemove.size().width(), self.btnQueueRemove.y())
 | |
| 
 | |
|         self.lblNotMuted.move(8, 8)
 | |
|         self.unmutedList.setGeometry(8, 24, 160, 192)
 | |
|         self.mutedList.setGeometry(238, 24, 160, 192)
 | |
|         self.lblMuted.move(238 + self.mutedList.size().width() - self.mutedList.size().width() - 8, 8)
 | |
|         self.btnMute.setGeometry((714 - 304) / 2 - 26, 64, 48, 32)
 | |
|         self.btnUnmute.setGeometry((714 - 304) / 2 - 26, 128, 48, 32)
 | |
| 
 | |
|         self.iniSwapList.setGeometry(8, 8, self.gameTabs.width() - 16, self.iniSwapList.sizeHint().height())
 | |
|         self.btnIniSwapConfirm.resize(self.btnIniSwapRefresh.sizeHint())
 | |
|         self.btnIniSwapConfirm.move(8, 64)
 | |
|         self.btnIniSwapReset.resize(self.btnIniSwapRefresh.sizeHint())
 | |
|         self.btnIniSwapReset.move(8, self.btnIniSwapConfirm.y() + self.btnIniSwapConfirm.size().height() + 8)
 | |
|         self.btnIniSwapRefresh.resize(self.btnIniSwapRefresh.sizeHint())
 | |
|         self.btnIniSwapRefresh.move(8, self.btnIniSwapReset.y() + self.btnIniSwapReset.size().height() + 8)
 | |
|         self.lblIniSwapInfo.setGeometry(8, 32, 192, 24)
 | |
| 
 | |
|         self.cbPair.setGeometry(16, 16, 128, 24)
 | |
|         self.boxPair.setGeometry(112, 20, 192, 18)
 | |
|         self.sliPairOffset.setGeometry(114, 48, 192, 24)
 | |
|         self.lblPairOffset.move(self.sliPairOffset.x() - 88, self.sliPairOffset.y()+4)
 | |
|         self.sliPairOffsetY.setGeometry(114, 72, 24, 112)
 | |
|         self.lblPairOffsetY.move(self.lblPairOffset.x(), self.lblPairOffset.y()+64)
 | |
|         self.btnPairOffsetReset.move(self.sliPairOffset.x() + self.sliPairOffset.size().width() + 8, self.lblPairOffsetY.y())
 | |
|         self.lblPairOrder.move(self.lblPairOffset.x(), self.lblPairOffset.y()+144)
 | |
|         self.boxPairOrder.setGeometry(self.sliPairOffset.x(), self.lblPairOrder.y()-4, 80, self.btnPairOffsetReset.sizeHint().height())
 | |
| 
 | |
|         ## Sidebar
 | |
|         oocBottom = self.OOCNameInput.y() + self.OOCNameInput.height() # 268
 | |
|         self.OOCLogin.resize(48, 20)
 | |
|         self.OOCLogin.move(viewportRight + 14 + self.OOCLog.size().width() - (self.OOCLogin.size().width()), oocBottom + 6)
 | |
| 
 | |
|         # Server tabs
 | |
|         serverTabsHeight = self.serverTabs.height() - self.serverTabs.findChild(QtGui.QTabBar).height()
 | |
|         
 | |
|         self.musicItems.setGeometry(8, 8, self.serverTabs.width() - 20, serverTabsHeight - self.musicSearch.sizeHint().height() - 20)
 | |
|         self.btnMusicOptions.setGeometry(self.musicItems.x() + self.musicItems.width() - self.btnMusicOptions.sizeHint().width(), self.musicItems.size().height() + 16, self.btnMusicOptions.sizeHint().width(), self.musicSearch.sizeHint().height())
 | |
|         self.musicSearch.setGeometry(8, self.btnMusicOptions.y(), self.musicItems.width() - self.btnMusicOptions.width() - 4, self.musicSearch.sizeHint().height())
 | |
| 
 | |
|         self.playerItems.setGeometry(8, 8, self.serverTabs.width() - 20, serverTabsHeight - self.btnPlayerPair.sizeHint().height() - 20)
 | |
|         self.btnPlayerPair.resize(self.btnPlayerPair.sizeHint())
 | |
|         self.btnPlayerKick.resize(self.btnPlayerKick.sizeHint())
 | |
|         self.btnPlayerBan.resize(self.btnPlayerBan.sizeHint())
 | |
|         self.btnPlayerPair.move(8, self.playerItems.size().height() + 16)
 | |
|         self.btnPlayerKick.move(8 + self.btnPlayerPair.x() + self.btnPlayerPair.size().width(), self.playerItems.size().height() + 16)
 | |
|         self.btnPlayerBan.move(8 + self.btnPlayerKick.x() + self.btnPlayerKick.size().width(), self.playerItems.size().height() + 16)
 | |
| 
 | |
|         self.backgroundItems.setGeometry(8, 8, self.serverTabs.width() - 20, serverTabsHeight - self.btnBackgroundsRefresh.sizeHint().height() - 20)
 | |
|         self.backgroundSearch.setGeometry(8, self.backgroundItems.size().height() + 16, self.serverTabs.width() - 20 - self.btnBackgroundsRefresh.sizeHint().width() - 20, self.backgroundSearch.sizeHint().height())
 | |
|         self.btnBackgroundsRefresh.resize(self.btnBackgroundsRefresh.sizeHint().width(), self.backgroundSearch.height())
 | |
|         self.btnBackgroundsRefresh.move(self.backgroundItems.width() - self.btnBackgroundsRefresh.width(), self.backgroundItems.size().height() + 16)
 | |
| 
 | |
|     def resetPairOffsets(self):
 | |
|         self.sliPairOffset.setValue(0)
 | |
|         self.sliPairOffsetY.setValue(0)
 | |
| 
 | |
|     def screenShakeTick(self):
 | |
|         self.shakesRemaining -= 1
 | |
|         shakeForce = 8
 | |
|         if self.shakesRemaining:
 | |
|             self.court.move(random.randint(-shakeForce, shakeForce), random.randint(-shakeForce, shakeForce))
 | |
|             self.zoom.move(random.randint(-shakeForce, shakeForce), random.randint(-shakeForce, shakeForce))
 | |
|             self.char.move(self.char.xx + random.randint(-shakeForce, shakeForce), self.char.yy + random.randint(-shakeForce, shakeForce), True)
 | |
|             self.sideChar.move(self.sideChar.xx + random.randint(-shakeForce, shakeForce), self.sideChar.yy + random.randint(-shakeForce, shakeForce), True)
 | |
|             self.chatbox.move(self.chatbox.initial.x() + random.randint(-shakeForce, shakeForce), self.chatbox.initial.y() +  random.randint(-shakeForce, shakeForce))
 | |
|         else:
 | |
|             self.court.move(0,0)
 | |
|             self.zoom.move(0,0)
 | |
|             self.char.move(self.char.xx, self.char.yy, True)
 | |
|             self.sideChar.move(self.sideChar.xx, self.sideChar.yy, True)
 | |
|             self.chatbox.move(self.chatbox.initial.topLeft())
 | |
|             self.screenshake.stop()
 | |
|     
 | |
|     def ICChatFocus(self):
 | |
|         self.ICChatInput.setFocus()
 | |
| 
 | |
|     def onRealizationClicked(self):
 | |
|         if self.btnRealization.isPressed():
 | |
|             self.boxEffects.setCurrentIndex(1) # realization
 | |
|         elif self.boxEffects.currentText() == "realization":
 | |
|             self.boxEffects.setCurrentIndex(0)
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def onShakeClicked(self):
 | |
|         self.cbPreanim.setChecked(False)
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def onOOCLoginClicked(self):
 | |
|         if not self.OOCNameInput.text():
 | |
|             self.OOCNameInput.setText("unnamed")
 | |
|         
 | |
|         if not self.login:
 | |
|             password, ok = QtGui.QInputDialog.getText(self, "Login as moderator", "Enter password.")
 | |
|             if password and ok:
 | |
|                 self.sendOOCchat(self.OOCNameInput.text().toUtf8(), "/login")
 | |
|                 self.sendOOCchat(self.OOCNameInput.text().toUtf8(), password.toUtf8())
 | |
|         else:
 | |
|             self.sendOOCchat(self.OOCNameInput.text().toUtf8(), "/logout")
 | |
|     
 | |
|     def setPing(self, newping):
 | |
|         self.lblPing.setText("Ping: %d" % newping)
 | |
|     
 | |
|     def setPosition(self, ind):
 | |
|         if not self.OOCNameInput.text():
 | |
|             self.OOCNameInput.setText("unnamed")
 | |
|         self.boxPositions.setCurrentIndex(ind)
 | |
|         self.charSide = str(self.boxPositions.itemText(ind))
 | |
|         self.setJudgeButtons()
 | |
|         self.ICChatFocus()
 | |
|         
 | |
|         if self.demoPlaying:
 | |
|             return
 | |
| 
 | |
|         server_is_2_8 = "additive" in self.features and "looping_sfx" in self.features and "effects" in self.features
 | |
|             
 | |
|         if server_is_2_8:
 | |
|             self.tcp.send("SP#"+self.charSide+"#%") # all hail new AO 2.8 packet
 | |
|         else:
 | |
|             self.sendOOCchat(self.OOCNameInput.text().toUtf8(), "/pos "+self.charSide)
 | |
|     
 | |
|     def changeMusicVolume(self, value):
 | |
|         if self.music:
 | |
|             audio.setHandleAttr(self.music, BASS_ATTRIB_VOL, value / 100.0)
 | |
|             if value == 0:
 | |
|                 audio.pauseHandle(self.music)
 | |
|             elif audio.handleIsActive(self.music) == BASS_ACTIVE_PAUSED:
 | |
|                 audio.playHandle(self.music, False)
 | |
|     
 | |
|     def changeSoundVolume(self, value):
 | |
|         for s in self.sound:
 | |
|             if s:
 | |
|                 audio.setHandleAttr(self.sound, BASS_ATTRIB_VOL, value / 100.0)
 | |
|         audio.setHandleAttr(self.sndRealization, BASS_ATTRIB_VOL, value / 100.0)
 | |
|         audio.setHandleAttr(self.wtceSfx, BASS_ATTRIB_VOL, value / 100.0)
 | |
|         audio.setHandleAttr(self.guiltySfx, BASS_ATTRIB_VOL, value / 100.0)
 | |
|         audio.setHandleAttr(self.notGuiltySfx, BASS_ATTRIB_VOL, value / 100.0)
 | |
|         if self.modcall:
 | |
|             audio.setHandleAttr(self.modcall, BASS_ATTRIB_VOL, value / 100.0)
 | |
|     
 | |
|     def changeBlipVolume(self, value):
 | |
|         if self.blipSound:
 | |
|             audio.setHandleAttr(self.blipSound, BASS_ATTRIB_VOL, value / 100.0)
 | |
|     
 | |
|     def setJudgeButtons(self):
 | |
|         if self.charSide == 'jud':
 | |
|             self.btnDefenseBar.btnMinus.show()
 | |
|             self.btnDefenseBar.btnPlus.show()
 | |
|             self.btnProsecutionBar.btnMinus.show()
 | |
|             self.btnProsecutionBar.btnPlus.show()
 | |
|             self.btnWitnessTestimony.show()
 | |
|             self.btnCrossExamination.show()
 | |
|             self.btnNotGuilty.show()
 | |
|             self.btnGuilty.show()
 | |
|         else:
 | |
|             self.btnDefenseBar.btnMinus.hide()
 | |
|             self.btnDefenseBar.btnPlus.hide()
 | |
|             self.btnProsecutionBar.btnMinus.hide()
 | |
|             self.btnProsecutionBar.btnPlus.hide()
 | |
|             self.btnWitnessTestimony.hide()
 | |
|             self.btnCrossExamination.hide()
 | |
|             self.btnNotGuilty.hide()
 | |
|             self.btnGuilty.hide()
 | |
|     
 | |
|     def onShownameChanged(self, text):
 | |
|         self.showname = str(text.toUtf8())
 | |
| 
 | |
|     def onMusicItemClicked(self, item):
 | |
|         self.actMusicCopy.setDisabled(False)
 | |
|         # self.actMusicEdit.setDisabled(False)
 | |
|         # self.actMusicDelete.setDisabled(False)
 | |
|     
 | |
|     def onMusicItemDoubleClicked(self, item):
 | |
|         self.pickedMusicItem = True
 | |
|         if self.privateMusicSelected:
 | |
|             self.sendOOCchat(self.OOCNameInput.text().toUtf8(), "/play " + encodeAOString(self.musicListPrivate[item.text()]))
 | |
|         else:
 | |
|             self.sendMC(self.musicList[item.text()])
 | |
|         
 | |
|     def onMusicSearch(self, text):
 | |
|         self.musicItems.clear()
 | |
|         self.actMusicCopy.setDisabled(True)
 | |
|         self.actMusicEdit.setDisabled(True)
 | |
|         self.actMusicDelete.setDisabled(True)
 | |
|         
 | |
|         _musicList = self.musicListPrivate if self.privateMusicSelected else self.musicList
 | |
|         
 | |
|         if text:
 | |
|             for song, fname in _musicList.items():
 | |
|                 if QtCore.QString(fname).contains(text, QtCore.Qt.CaseInsensitive):
 | |
|                     songitem = QtGui.QListWidgetItem()
 | |
|                     songitem.setText(song)
 | |
|                     if not self.privateMusicSelected and exists(unicode(AOpath + 'sounds/music/' + decodeAOString(fname).lower())):
 | |
|                         songitem.setBackgroundColor(QtGui.QColor(self.foundSongItemColor))
 | |
|                     self.musicItems.addItem(songitem)
 | |
|         else:
 | |
|             self.loadAllMusic()
 | |
|     
 | |
|     def onMusicOptionsClicked(self):
 | |
|         self.mnuMusicOptions.exec_(QtGui.QCursor.pos())
 | |
|     
 | |
|     def onActMusicRandomTriggered(self):
 | |
|         _musicList = self.musicListPrivate if self.privateMusicSelected else self.musicList
 | |
|         choice = random.randint(0, self.musicItems.count() - 1)
 | |
|         _item = self.musicItems.item(choice)
 | |
|         self.musicItems.setCurrentItem(_item)
 | |
|         self.actMusicCopy.setDisabled(False)
 | |
|         # self.actMusicEdit.setDisabled(False)
 | |
|         # self.actMusicDelete.setDisabled(False)
 | |
|         self.onMusicItemDoubleClicked(_item)
 | |
|         
 | |
|     def onActMusicCopyTriggered(self):
 | |
|         QtGui.QApplication.clipboard().setText(self.musicItems.currentItem().text())
 | |
|     
 | |
|     def onActMusicAddTriggered(self):
 | |
|         title, ok = QtGui.QInputDialog.getText(self, "Add new song", "Please enter a title for the song. Leave this empty to add a separator that acts as music stop.")
 | |
|         url = QtCore.QString("")
 | |
|         if ok:
 | |
|             ok = False
 | |
|             if not title:
 | |
|                 title = QtCore.QString("--------------------------")
 | |
|                 ok = True
 | |
|             if not ok:
 | |
|                 url, ok = QtGui.QInputDialog.getText(self, "Add new song", "Please enter an URL for the song.")
 | |
|                 if ok:
 | |
|                     title.replace("=", "-")
 | |
|             if ok:
 | |
|                 if not url:
 | |
|                     url = "~stop.mp3"
 | |
|                 with open(AO2XPpath + "music.ini", "ab") as f:
 | |
|                     f.write(("\n" + title + " = " + url).toUtf8())
 | |
|                 self.onActMusicRefreshTriggered()
 | |
|     
 | |
|     def onActMusicAddCurrentTriggered(self):
 | |
|         title, ok = QtGui.QInputDialog.getText(self, "Add currently playing song", "Please enter a title for the song.")
 | |
|         if title and ok:
 | |
|             with open(AO2XPpath + "music.ini", "ab") as f:
 | |
|                 f.write(("\n" + title + " = " + self.currentMusicURL).toUtf8())
 | |
|             if self.privateMusicSelected:
 | |
|                 self.onActMusicRefreshTriggered()
 | |
|         
 | |
|     def onActMusicEditTriggered(self):
 | |
|         pass
 | |
|         
 | |
|     def onActMusicDeleteTriggered(self):
 | |
|         pass
 | |
|         
 | |
|     def onActMusicEditExternalTriggered(self):
 | |
|         path = AO2XPpath + "music.ini"
 | |
|         if platform.system() == 'Windows':
 | |
|             os.startfile(path)
 | |
|         else:
 | |
|             subprocess.call(('xdg-open', path))
 | |
|         
 | |
|     def onActMusicRefreshTriggered(self, init=False):
 | |
|         if exists(AO2XPpath + "music.ini"):
 | |
|             self.musicListPrivate = ini.sectionless_ini_to_dict(AO2XPpath + "music.ini", QtCore.QString)
 | |
|         if not init:
 | |
|             self.musicItems.clear()
 | |
|             self.loadAllMusic()
 | |
|         
 | |
|     def onActMusicSwitchTriggered(self):
 | |
|         self.privateMusicSelected = not self.privateMusicSelected
 | |
|         
 | |
|         self.actMusicSeparator.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicAdd.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicEdit.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicDelete.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicEditExternal.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicRefresh.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicSwitchToGlobal.setVisible(self.privateMusicSelected)
 | |
|         self.actMusicSwitchToPrivate.setVisible(not self.privateMusicSelected)
 | |
|         
 | |
|         self.musicItems.clear()
 | |
|         self.musicSearch.blockSignals(True)
 | |
|         self.musicSearch.clear()
 | |
|         self.musicSearch.blockSignals(False)
 | |
|         self.actMusicCopy.setDisabled(True)
 | |
|         self.loadAllMusic()
 | |
|             
 | |
|     def loadBackgrounds(self):
 | |
|         self.backgroundItems.clear()
 | |
|         self.backgroundSearch.clear()
 | |
|         self.backgrounds = []
 | |
|         for folder in os.listdir(unicode(AOpath + 'background')):
 | |
|             self.backgrounds.append(folder)
 | |
|             self.backgroundItems.addItem(folder)
 | |
|             
 | |
|     def onBackgroundSearch(self, text):
 | |
|         self.backgroundItems.clear()
 | |
|         
 | |
|         if text:
 | |
|             for bg in self.backgrounds:
 | |
|                 if QtCore.QString(bg).contains(text, QtCore.Qt.CaseInsensitive):
 | |
|                     self.backgroundItems.addItem(bg)
 | |
|         else:
 | |
|             for bg in self.backgrounds:
 | |
|                 self.backgroundItems.addItem(bg)
 | |
| 
 | |
|     def setEvidenceImage(self, guiobj, image, scale=False):
 | |
|         if exists(AOpath + 'evidence/' + image):
 | |
|             img = QtGui.QPixmap(AOpath + "evidence/%s" % image)
 | |
|             if not img.isNull() and scale:
 | |
|                 guiobj.setPixmap(img.scaled(140, 140,  QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
|             else:
 | |
|                 guiobj.setPixmap(img)
 | |
|         else:
 | |
|             img = QtGui.QPixmap(AO2XPpath + 'themes/default/evidence_selected.png')
 | |
|             if not img.isNull() and scale:
 | |
|                 guiobj.setPixmap(img.scaled(140, 140,  QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
|             else:
 | |
|                 guiobj.setPixmap(img)
 | |
|                 
 | |
|             if ini.read_ini_bool("AO2XP.ini", "General", "download evidence", True):
 | |
|                 url = "base/evidence/"+image.lower()
 | |
|                 url = url.replace("evidence/../", "")
 | |
|                 path = AOpath + "evidence/"+image
 | |
|                 path = path.replace("evidence/../", "")
 | |
|                 thread.start_new_thread(downloadThread, (url, path))
 | |
|     
 | |
|     def changeUnmuteIndex(self, item):
 | |
|         for i in range(self.unmutedList.count()):
 | |
|             if self.unmutedList.item(i) == item:
 | |
|                 self.muteSelected = i
 | |
| 
 | |
|     def changeMuteIndex(self, item):
 | |
|         for i in range(self.mutedList.count()):
 | |
|             if self.mutedList.item(i) == item:
 | |
|                 self.unmuteSelected = i
 | |
| 
 | |
|     def onMuteClicked(self):
 | |
|         if self.unmutedList.count() == 0:
 | |
|             return QtGui.QMessageBox.information(self, 'No character selected', 'There are no characters to mute.')
 | |
|         if self.muteSelected == -1:
 | |
|             return QtGui.QMessageBox.information(self, 'No character selected', 'To mute a character, select their name from the list to the left, then click the >> button.')
 | |
|         for i in range(len(self.charList)):
 | |
|             if self.charList[i][0] == self.unmutedList.item(self.muteSelected).text():
 | |
|                 self.muted.append(i)
 | |
|                 self.muted.sort()
 | |
|                 self.muteSelected = -1
 | |
|                 break
 | |
| 
 | |
|         self.unmutedList.clear()
 | |
|         self.mutedList.clear()
 | |
|         for i in range(len(self.charList)):
 | |
|             if i in self.muted:
 | |
|                 self.mutedList.addItem(self.charList[i][0])
 | |
|             else:
 | |
|                 self.unmutedList.addItem(self.charList[i][0])
 | |
| 
 | |
|     def onUnmuteClicked(self):
 | |
|         if self.mutedList.count() == 0:
 | |
|             return QtGui.QMessageBox.information(self, 'No character selected', "There are no characters to unmute.")
 | |
|         if self.unmuteSelected == -1:
 | |
|             return QtGui.QMessageBox.information(self, 'No character selected', 'To unmute a character, select their name from the list to the right, then click the << button.')
 | |
|         for char in self.charList:
 | |
|             if char[0] == self.mutedList.item(self.unmuteSelected).text():
 | |
|                 del self.muted[self.unmuteSelected]
 | |
|                 self.unmuteSelected = -1
 | |
|                 break
 | |
| 
 | |
|         self.unmutedList.clear()
 | |
|         self.mutedList.clear()
 | |
|         for i in range(len(self.charList)):
 | |
|             if i in self.muted:
 | |
|                 self.mutedList.addItem(self.charList[i][0])
 | |
|             else:
 | |
|                 self.unmutedList.addItem(self.charList[i][0])
 | |
| 
 | |
|     def onPenaltyBarMinusClicked(self, barType):
 | |
|         netmsg = 'HP#' + str(barType) + '#'
 | |
|         if barType == 1:
 | |
|             if self.btnDefenseBar.getHealth() <= 0:
 | |
|                 return
 | |
|             netmsg += str(self.btnDefenseBar.getHealth() - 1) + '#'
 | |
|         elif barType == 2:
 | |
|             if self.btnProsecutionBar.getHealth() <= 0:
 | |
|                 return
 | |
|             netmsg += str(self.btnProsecutionBar.getHealth() - 1) + '#'
 | |
|         netmsg += '%'
 | |
|         self.tcp.send(netmsg)
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def onPenaltyBarPlusClicked(self, barType):
 | |
|         netmsg = 'HP#' + str(barType) + '#'
 | |
|         if barType == 1:
 | |
|             if self.btnDefenseBar.getHealth() >= 10:
 | |
|                 return
 | |
|             netmsg += str(self.btnDefenseBar.getHealth() + 1) + '#'
 | |
|         elif barType == 2:
 | |
|             if self.btnProsecutionBar.getHealth() >= 10:
 | |
|                 return
 | |
|             netmsg += str(self.btnProsecutionBar.getHealth() + 1) + '#'
 | |
|         netmsg += '%'
 | |
|         self.tcp.send(netmsg)
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def setWhiteFlash(self, on, realizationtype=0, msec=0):
 | |
|         self.whiteFlashLabel.setVisible(on)
 | |
|         if realizationtype == 1:
 | |
|             self.playRealization(f)
 | |
|         if msec:
 | |
|             self.whiteFlash.start(msec)
 | |
| 
 | |
|     def setScreenShake(self, on, amount=20):
 | |
|         self.shakesRemaining = amount if on else 1
 | |
|         self.screenshake.start(25)
 | |
| 
 | |
|     def OnWTCEButtonClicked(self, type, variant):
 | |
|         if type != 2:
 | |
|             self.tcp.send('RT#testimony' + str(type + 1) + '#%')
 | |
|         else:
 | |
|             self.tcp.send("RT#judgeruling#" +str(variant)+ "#%")
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def onPVPacket(self, charName=""):
 | |
|         self.gamewindow.setFixedSize(self.width, self.height)
 | |
|         self.gamewindow.center()
 | |
|         if not self.swapping and charName:
 | |
|             self.loadCharacter(charName)
 | |
|     
 | |
|     def loadCharacter(self, charName):
 | |
|         self.queueItems.clear()
 | |
|         self.messageQueue = []
 | |
|         self.boxEffects.clear()
 | |
|         self.boxEmotes.clear()
 | |
|         self.charEmotes = []
 | |
|         self.selectedEmote = 0
 | |
|         self.currentEmotePage = 0
 | |
|         
 | |
|         self.swapping = False
 | |
|         self.lblIniSwapInfo.setText('Not swapped')
 | |
|         
 | |
|         effectsList = ini.get_effects(charName)
 | |
|         self.boxEffects.setVisible(bool(effectsList))
 | |
|         if effectsList:
 | |
|             effectsList.insert(0, "No effect")
 | |
|             self.boxEffects.addItems(effectsList)
 | |
|         
 | |
|         if isinstance(charName, str):
 | |
|             charName = unicode(charName.lower())
 | |
|         elif isinstance(charName, QtCore.QString):
 | |
|             charName = unicode(charName.toLower())
 | |
|         
 | |
|         #self.charName = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "options", "name", charName.decode('utf-8').lower()
 | |
|         self.charName = charName # Just use the folder name
 | |
| 
 | |
|         self.charShowname = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "options", "showname")
 | |
|         if not self.charShowname == "":
 | |
|             self.charShowname = self.charShowname.decode('utf-8')
 | |
|         self.charSide = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "options", "side", "def")
 | |
|         
 | |
|         self.boxPositions.setCurrentIndex(self.boxPositions.findText(self.charSide))
 | |
|         self.setJudgeButtons()
 | |
| 
 | |
|         for emoteind in range(1, ini.read_ini_int(AOpath + "characters/"+self.charName+"/char.ini", "emotions", "number") + 1):
 | |
|             if emoteind == 1:
 | |
|                 suffix = 'on'
 | |
|             else:
 | |
|                 suffix = 'off'
 | |
|             
 | |
|             emote = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "emotions", str(emoteind), 'normal#(a)normal#normal#0#')
 | |
|             sound = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "soundn", str(emoteind), '1')
 | |
|             soundt = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "soundt", str(emoteind), '0')
 | |
|             soundl = ini.read_ini(AOpath + 'characters/' + charName + '/char.ini', "soundl", str(emoteind), '0') # AO 2.8
 | |
|             
 | |
|             emoteList = emote.split('#')
 | |
|             deskmod = emoteList.pop(len(emoteList) - 1)
 | |
|             
 | |
|             emoteList.append(sound)
 | |
|             emoteList.append(soundt)
 | |
|             emoteList.append(soundl) # AO 2.8
 | |
|             emoteList.append(deskmod)
 | |
|             self.charEmotes.append(emoteList)
 | |
|             if emoteList[0]:
 | |
|                 self.boxEmotes.addItem(emoteList[0])
 | |
|             else:
 | |
|                 self.boxEmotes.addItem(emoteList[1] + ' ' + emoteList[2])
 | |
| 
 | |
|         self.boxEmotes.setCurrentIndex(0)
 | |
|         self.setEmotePage()
 | |
| 
 | |
|     def setEmotePage(self):
 | |
|         if self.myChar < 0:
 | |
|             return
 | |
|         self.btnPrevEmotePage.hide()
 | |
|         self.btnNextEmotePage.hide()
 | |
| 
 | |
|         totalEmotes = len(self.charEmotes) 
 | |
|         
 | |
|         for button in self.emoteButtons:
 | |
|             button.hide()
 | |
|             
 | |
|         if not totalEmotes:
 | |
|             print "[client] The selected character appears to have no emotions defined"
 | |
|             return
 | |
| 
 | |
|         totalPages = totalEmotes / self.maxEmotesOnPage
 | |
|         emotesOnPage = 0
 | |
|         if totalEmotes % self.maxEmotesOnPage != 0:
 | |
|             totalPages += 1
 | |
|             if totalPages > self.currentEmotePage + 1:
 | |
|                 emotesOnPage = self.maxEmotesOnPage
 | |
|             else:
 | |
|                 emotesOnPage = totalEmotes % self.maxEmotesOnPage
 | |
|         else:
 | |
|             emotesOnPage = self.maxEmotesOnPage
 | |
|         if totalPages > self.currentEmotePage + 1:
 | |
|             self.btnNextEmotePage.show()
 | |
|         if self.currentEmotePage > 0:
 | |
|             self.btnPrevEmotePage.show()
 | |
|         for nEmote in range(emotesOnPage):
 | |
|             nRealEmote = nEmote + self.currentEmotePage * self.maxEmotesOnPage
 | |
|             if nRealEmote == self.selectedEmote:
 | |
|                 image = QtGui.QPixmap(AOpath + 'characters/' + self.charName + '/emotions/button' + str(nRealEmote + 1) + '_on.png')
 | |
|             else:
 | |
|                 image = QtGui.QPixmap(AOpath + 'characters/' + self.charName + '/emotions/button' + str(nRealEmote + 1) + '_off.png')
 | |
|                 
 | |
|             if not image.isNull() and not image.width() == 40:
 | |
|                 self.emoteButtons[nEmote].setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.SmoothTransformation))
 | |
|             else:
 | |
|                 self.emoteButtons[nEmote].setPixmap(image)
 | |
|                 
 | |
|             self.emoteButtons[nEmote].show()
 | |
|             self.emoteButtons[nEmote].setToolTip(self.charEmotes[nEmote + self.currentEmotePage * self.maxEmotesOnPage][0])       
 | |
|             
 | |
|     def iniSwapIndexChange(self, ind):
 | |
|         self.iniSwapIndex = ind
 | |
| 
 | |
|     def loadSwapCharacters(self):
 | |
|         self.charsFolder = []
 | |
|         self.iniSwapList.clear()
 | |
|         for folder in os.listdir(unicode(AOpath + 'characters')):
 | |
|             if exists(AOpath + 'characters/' + folder + '/char.ini'):
 | |
|                 self.charsFolder.append(folder)
 | |
|                 self.iniSwapList.addItem(folder)
 | |
| 
 | |
|     def onIniSwapConfirmClicked(self):
 | |
|         if self.charList[self.myChar][0].lower() == self.charsFolder[self.iniSwapIndex].lower():
 | |
|             self.resetIniSwap()
 | |
|         else:
 | |
|             self.swapping = True
 | |
|             self.lblIniSwapInfo.setText('Swapped to ' + self.charsFolder[self.iniSwapIndex])
 | |
|             self.loadCharacter(self.charsFolder[self.iniSwapIndex])
 | |
| 
 | |
|     def resetIniSwap(self):
 | |
|         self.swapping = False
 | |
|         self.lblIniSwapInfo.setText('Not swapped')
 | |
|         self.loadCharacter(self.charList[self.myChar][0])
 | |
| 
 | |
|     def onAddEvidence(self):
 | |
|         self.evidenceEditor.show()
 | |
| 
 | |
|     def onEditEvidence(self):
 | |
|         if not self.evidence:
 | |
|             return QtGui.QMessageBox.information(self, 'No evidence', "There's no evidence on the court record.")
 | |
|         self.evidenceEditor.editEvidence(self.selectedEvidence)
 | |
| 
 | |
|     def onDeleteEvidence(self):
 | |
|         if self.selectedEvidence == -1:
 | |
|             return
 | |
|             
 | |
|         if not self.privateInventorySelected:
 | |
|             if self.evidence:
 | |
|                 self.tcp.send('DE#' + str(self.selectedEvidence) + '#%')
 | |
|             else:
 | |
|                 self.tcp.send('DE#0#%')
 | |
|         elif len(self.privateEvidence):
 | |
|             del self.privateEvidence[self.selectedEvidence]
 | |
|             self.boxPrivateEvidence.removeItem(self.selectedEvidence)
 | |
|             
 | |
|     def onExportEvidence(self, isAutosave=False):
 | |
|         if not exists("evidence"):
 | |
|             os.mkdir("evidence")
 | |
|             
 | |
|         path = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save evidence", "evidence", "Evidence (*.ini)")) if not isAutosave else "evidence/inventory.ini"
 | |
|         
 | |
|         if path:
 | |
|             evidence = self.evidence if not self.privateInventorySelected else self.privateEvidence
 | |
|             inifile = ConfigParser()
 | |
|             for i in range(len(evidence)):
 | |
|                 evi = evidence[i]
 | |
|                 id = str(i)
 | |
|                 inifile.add_section(id)
 | |
|                 if isinstance(evi[0], QtCore.QString):
 | |
|                     inifile.set(id, "name", evi[0].replace('\n', '\\n').toUtf8())
 | |
|                 else:
 | |
|                     inifile.set(id, "name", evi[0].replace('\n', '\\n').encode('utf-8'))
 | |
|                     
 | |
|                 if isinstance(evi[1], QtCore.QString):
 | |
|                     inifile.set(id, "description", evi[1].replace('\n', '\\n').toUtf8())
 | |
|                 else:
 | |
|                     inifile.set(id, "description", evi[1].replace('\n', '\\n').encode('utf-8'))
 | |
|                     
 | |
|                 if isinstance(evi[2], QtCore.QString):
 | |
|                     inifile.set(id, "image", evi[2].toUtf8())
 | |
|                 else:
 | |
|                     inifile.set(id, "image", evi[2].encode('utf-8'))
 | |
|             
 | |
|             with open(path, "wb") as f:
 | |
|                 inifile.write(f)
 | |
|     
 | |
|     def onImportEvidence(self, is_autoload=False):
 | |
|         if not is_autoload:
 | |
|             if not self.privateInventorySelected:
 | |
|                 if QtGui.QMessageBox.warning(self, "Import evidence", 'This will OVERWRITE the global evidence server-side.\n\nContinue?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
 | |
|                     return
 | |
|             else:
 | |
|                 if QtGui.QMessageBox.warning(self, "Import evidence", 'This will OVERWRITE your private evidence.\n\nContinue?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
 | |
|                     return
 | |
| 
 | |
|         if not exists("evidence"):
 | |
|             os.mkdir("evidence")
 | |
|             
 | |
|         path = unicode(QtGui.QFileDialog.getOpenFileName(self, "Load evidence", "evidence", "Evidence (*.ini)")) if not is_autoload else "evidence/inventory.ini"
 | |
|         if path and exists(path):
 | |
|             evidence = []
 | |
|             inifile = ConfigParser()
 | |
|             inifile.read(path)
 | |
|             for section in inifile.sections():
 | |
|                 name = ini.read_ini(inifile, section, "name").replace('\\n', '\n').replace('\\"', '"').rstrip()
 | |
|                 description = ini.read_ini(inifile, section, "description").replace('\\n', '\n').replace('\\"', '"').rstrip()
 | |
|                 image = ini.read_ini(inifile, section, "image", "empty.png")
 | |
|                 
 | |
|                 # Remove opening and closing quotes
 | |
|                 if description[0] == '"' and description[-1] == '"':
 | |
|                     description = description[1:-1]
 | |
|                     
 | |
|                 # Not all evidence files are plain unicode
 | |
|                 name = name.decode("unicode_escape") if "\\x" in name else name.decode('utf-8')
 | |
|                 description = description.decode("unicode_escape") if "\\x" in description else description.decode('utf-8')
 | |
|                 
 | |
|                 evidence.append([name, description, image])
 | |
|                 
 | |
|             if self.privateInventorySelected or is_autoload:
 | |
|                 dropdown = self.boxPrivateEvidence
 | |
|                 self.privateEvidence = evidence
 | |
|                 if dropdown.count() > 0:
 | |
|                     dropdown.clear()
 | |
| 
 | |
|                 if evidence:
 | |
|                     for evi in evidence:
 | |
|                         dropdown.addItem(evi[0])
 | |
|                     dropdown.setCurrentIndex(self.selectedEvidence)
 | |
|                 
 | |
|                 if not is_autoload:
 | |
|                     self.onExportEvidence(True)
 | |
|             elif evidence:
 | |
|                 if self.evidence:
 | |
|                     for i in range(len(self.evidence)):
 | |
|                         self.tcp.send('DE#' + str(self.selectedEvidence) + '#%')
 | |
|                 for evi in evidence:
 | |
|                     self.tcp.send('PE#' + evi[0] + '#' + evi[1] + '#' + evi[2] + '#%')
 | |
|          
 | |
|     def onTransferEvidence(self):
 | |
|         if self.privateInventorySelected:
 | |
|             evi = self.privateEvidence[self.selectedEvidence]
 | |
|             target = self.evidence
 | |
|             target_str = "global"
 | |
|         else:
 | |
|             evi = self.evidence[self.selectedEvidence]
 | |
|             target = self.privateEvidence
 | |
|             target_str = "private"
 | |
|         
 | |
|         if evi in target:
 | |
|             return QtGui.QMessageBox.information(self, "Can't transfer evidence", 'The evidence "%s" already exists in the %s inventory.' % (evi[0], target_str))
 | |
|         else:
 | |
|             if self.privateInventorySelected:
 | |
|                 for i in range(len(evi)):
 | |
|                     evi[i] = encodeAOString(evi[i]).replace('\\n', '\n')
 | |
|                 self.tcp.send('PE#' + evi[0] + '#' + evi[1] + '#' + evi[2] + '#%')
 | |
|             else:
 | |
|                 self.privateEvidence.append(evi)
 | |
|                 self.boxPrivateEvidence.addItem(evi[0])
 | |
|         
 | |
|     def onTransferAllEvidence(self):
 | |
|         fail = []
 | |
|         
 | |
|         if self.privateInventorySelected:
 | |
|             evi = self.privateEvidence[self.selectedEvidence]
 | |
|             origin = self.privateEvidence
 | |
|             target = self.evidence
 | |
|             target_str = "global"
 | |
|         else:
 | |
|             evi = self.evidence[self.selectedEvidence]
 | |
|             origin = self.evidence
 | |
|             target = self.privateEvidence
 | |
|             target_str = "private"
 | |
|         
 | |
|         for evi in origin:
 | |
|             if evi in target:
 | |
|                 fail.append(evi[0])
 | |
|             else:
 | |
|                 if self.privateInventorySelected:
 | |
|                     self.tcp.send('PE#' + evi[0] + '#' + evi[1] + '#' + evi[2] + '#%')
 | |
|                 else:
 | |
|                     self.privateEvidence.append(evi)
 | |
|                     self.boxPrivateEvidence.addItem(evi[0])
 | |
|          
 | |
|         if fail:
 | |
|             return QtGui.QMessageBox.information(self, "Some evidence wasn't transferred", "The following evidence already exists in the %s inventory:\n\n%s." % (target_str, ", ".join(fail)))
 | |
|         
 | |
|     def onSwitchInventory(self, reset=False):
 | |
|         self.privateInventorySelected = not self.privateInventorySelected
 | |
|         if self.privateInventorySelected and not reset:
 | |
|             self.present = False
 | |
|             self.btnEvidencePresent.setPixmap(self.btnEvidencePresent.button_off)
 | |
|             self.btnEvidencePresent.hide()
 | |
|             self.boxEvidence.hide()
 | |
|             self.boxPrivateEvidence.show()
 | |
|             self.btnEvidenceMoveToGlobal.show()
 | |
|             self.btnEvidenceMoveAllToGlobal.show()
 | |
|             self.btnEvidenceSwitchToGlobal.show()
 | |
|             self.btnEvidenceMoveToPrivate.hide()
 | |
|             self.btnEvidenceMoveAllToPrivate.hide()
 | |
|             self.btnEvidenceSwitchToPrivate.hide()
 | |
|             self.boxPrivateEvidence.setCurrentIndex(0)
 | |
|             self.changeEvidence(0, 1)
 | |
|         else:
 | |
|             self.btnEvidencePresent.show()
 | |
|             self.boxEvidence.show()
 | |
|             self.boxPrivateEvidence.hide()
 | |
|             self.btnEvidenceMoveToGlobal.hide()
 | |
|             self.btnEvidenceMoveAllToGlobal.hide()
 | |
|             self.btnEvidenceSwitchToGlobal.hide()
 | |
|             self.btnEvidenceMoveToPrivate.show()
 | |
|             self.btnEvidenceMoveAllToPrivate.show()
 | |
|             self.btnEvidenceSwitchToPrivate.show()
 | |
|             self.boxEvidence.setCurrentIndex(0)
 | |
|             self.changeEvidence(0, 0)
 | |
| 
 | |
|     def onCallModClicked(self):
 | |
|         if "modcall_reason" in self.features:
 | |
|             reason, ok = QtGui.QInputDialog.getText(self, "Call a moderator", "Enter your reason.")
 | |
|             if ok and reason:
 | |
|                 self.tcp.send("ZZ#"+reason.toUtf8() + "#%")
 | |
|         else:
 | |
|             self.tcp.send("ZZ#%")
 | |
|             
 | |
|     def onReloadThemeClicked(self):
 | |
|         self.loadTheme()
 | |
| 
 | |
|     def onChangeCharClicked(self):
 | |
|         if self.demoPlaying:
 | |
|             self.inboxTimer.stop()
 | |
|             self.chatTickTimer.stop()
 | |
|             self.disconnectCommon()
 | |
|             self.gamewindow.returnToMenu()
 | |
|         else:
 | |
|             self.charSelect.showCharSelect()
 | |
| 
 | |
|     def changeFlipCheck(self, on):
 | |
|         if on == 2:
 | |
|             on = 1
 | |
|         self.myFlip = on
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def changePreanimCheck(self, on):
 | |
|         if on == 2:
 | |
|             on = 1
 | |
|         self.playPreanim = on
 | |
|         self.cbNoInterrupt.setDisabled(not on)
 | |
|         if on == 0:
 | |
|             self.cbNoInterrupt.setChecked(False)
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def onMessageQueueItemClicked(self, item):
 | |
|         for i in range(len(self.queueItems)):
 | |
|             if self.queueItems.item(i) == item:
 | |
|                 self.selectedMessage = i
 | |
| 
 | |
|     def onRemoveQueueClicked(self):
 | |
|         if len(self.queueItems) == 0:
 | |
|             return QtGui.QMessageBox.information(self, "No messages in queue", 'Enter a message on the game chat to add one.')
 | |
|         if self.selectedMessage == -1:
 | |
|             return QtGui.QMessageBox.information(self, 'No message selected', 'Select a message from the list to remove it.')
 | |
|         self.queueItems.takeItem(self.selectedMessage)
 | |
|         del self.messageQueue[self.selectedMessage]
 | |
|         
 | |
|     def onClearQueueClicked(self):
 | |
|         return QtGui.QMessageBox.information(self, "Clear queue", 'Not implemented.')
 | |
|                 
 | |
|     def onPlayerItemClicked(self, item):
 | |
|         for i in range(len(self.playerItems)):
 | |
|             sel = self.playerItems.item(i)
 | |
|             if sel == item:
 | |
|                 s = sel.text()
 | |
|                 self.selectedPlayer = s[1:s.indexOf("]")]
 | |
| 
 | |
|     def onPlayerPairClicked(self):
 | |
|         if not self.selectedPlayer == -1:
 | |
|             self.gameTabs.setCurrentWidget(self.tabPair)
 | |
|             self.cbPair.setChecked(True)
 | |
|             char = self.playerList[str(self.selectedPlayer)][1]
 | |
|             if char == '':
 | |
|                 return QtGui.QMessageBox.information(self, "Unable to pair", 'That player has no character selected.')
 | |
|             else:
 | |
|                 self.boxPair.setCurrentIndex([c[0] for c in self.charList].index(char))
 | |
|         else:
 | |
|             return QtGui.QMessageBox.information(self, 'No player selected', 'Select a player from the list to attempt pairing.')
 | |
| 
 | |
|     def onPlayerKickClicked(self):
 | |
|         if not self.selectedPlayer == -1:
 | |
|             reason, ok = QtGui.QInputDialog.getText(self, "Kick a player", "Please enter the reason.", text="Being annoying")
 | |
|             if reason and ok:
 | |
|                 self.tcp.send("MA#%s#0#%s#%%" % (self.selectedPlayer, reason))
 | |
|         else:
 | |
|             return QtGui.QMessageBox.information(self, 'No player selected', 'Select a player from the list to kick.')
 | |
|         
 | |
|     def onPlayerBanClicked(self):
 | |
|         if not self.selectedPlayer == -1:
 | |
|             reason, ok = QtGui.QInputDialog.getText(self, "Ban a player", "Please enter the reason.", text="Being annoying")
 | |
|             if reason and ok:
 | |
|                 duration, ok = QtGui.QInputDialog.getInt(self, "Ban a player", "Please enter the ban length in minutes.", 60, 1)
 | |
|                 if duration and ok:
 | |
|                     self.tcp.send("MA#%s#%s#%s#%%" % (self.selectedPlayer, duration, reason))
 | |
|         else:
 | |
|             return QtGui.QMessageBox.information(self, 'No player selected', 'Select a player from the list to ban.')
 | |
| 
 | |
|     def changeEvidence(self, ind, kind):
 | |
|         if ind < 0:
 | |
|             return
 | |
|         if self.privateInventorySelected:
 | |
|             if not kind == 1:
 | |
|                 return
 | |
|             evi = self.privateEvidence
 | |
|         else:
 | |
|             if not kind == 0:
 | |
|                 return
 | |
|             evi = self.evidence
 | |
|             
 | |
|         self.selectedEvidence = ind
 | |
|         if len(evi) > 0:
 | |
|             self.evidenceDescription.setText(evi[ind][1])
 | |
|             self.setEvidenceImage(self.evidenceImage, evi[ind][2])
 | |
|             
 | |
|     def changeGlobalEvidence(self, ind):
 | |
|         self.changeEvidence(ind, 0)
 | |
|         
 | |
|     def changePrivateEvidence(self, ind):
 | |
|         self.changeEvidence(ind, 1)
 | |
| 
 | |
|     def changeEmote(self, dropdown, ind):
 | |
|         if ind == -1:
 | |
|             return
 | |
|             
 | |
|         self.ICChatFocus()    
 | |
|         if not dropdown:
 | |
|             self.selectedEmote = ind + self.currentEmotePage * self.maxEmotesOnPage
 | |
|         else:
 | |
|             self.selectedEmote = ind
 | |
|         for button in self.emoteButtons:
 | |
|             if button.emoteid == ind:
 | |
|                 button.path = AOpath + 'characters/' + self.charName + '/emotions/button' + str(button.emoteid + self.currentEmotePage * self.maxEmotesOnPage + 1)
 | |
|                 image = QtGui.QPixmap(button.path + '_on.png')
 | |
|             else:
 | |
|                 image = QtGui.QPixmap(AOpath + 'characters/' + self.charName + '/emotions/button' + str(button.emoteid + self.currentEmotePage * self.maxEmotesOnPage + 1) + '_off.png')
 | |
|                 
 | |
|             if not image.isNull() and not image.width() == 40:
 | |
|                 button.setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.SmoothTransformation))
 | |
|             else:
 | |
|                 button.setPixmap(image)
 | |
| 
 | |
|     def setChatColor(self, ind):
 | |
|         self.myChatColor = ind
 | |
|         self.ICChatFocus()
 | |
| 
 | |
|     def showMessage(self, type, *args, **kwargs):
 | |
|         if type == 'critical':
 | |
|             reply = QtGui.QMessageBox.critical(self, *args, **kwargs)
 | |
|         elif type == 'information':
 | |
|             reply = QtGui.QMessageBox.information(self, *args, **kwargs)
 | |
|         elif type == 'question':
 | |
|             reply = QtGui.QMessageBox.question(self, *args, **kwargs)
 | |
|         elif type == 'warning':
 | |
|             reply = QtGui.QMessageBox.warning(self, *args, **kwargs)
 | |
|         if self.willDisconnect:
 | |
|             self.disconnectCommon()
 | |
|             self.gamewindow.returnToMenu()
 | |
|     
 | |
|     def disconnectCommon(self):
 | |
|         self.onSwitchInventory(True)
 | |
|         self.selectedPlayer = -1
 | |
|         self.playerItems.clear()
 | |
|         self.btnPlayerKick.setDisabled(True)
 | |
|         self.btnPlayerBan.setDisabled(True)
 | |
|         self.OOCLogin.setText("Lo&gin")
 | |
|         self.login = False
 | |
|         self.privateInventorySelected = False
 | |
|         self.setCurrentMusicURL(None)
 | |
|         if self.tcp:
 | |
|             self.tcp.close()
 | |
|         if self.demoPlayer:
 | |
|             self.demoPlayer.stop()
 | |
|             self.demoPlayer = None
 | |
|         self.demoRecorder = None
 | |
|         self.demoPlaying = False
 | |
|         self.stopMusic()
 | |
|             
 | |
|     def onAreaItemClicked(self, item):
 | |
|         area = item.text().split('\n')[0]
 | |
|         self.sendMC(area)
 | |
| 
 | |
|     def onBackgroundItemClicked(self, item):
 | |
|         self.sendOOCchat(self.OOCNameInput.text().toUtf8(), "/bg " + item.text())
 | |
| 
 | |
|     def sendMC(self, content):
 | |
|         if "cccc_ic_support" in self.features and self.showname:
 | |
|             self.tcp.send('MC#' + content + '#' + str(self.myChar) + '#' + self.showname.decode('utf-8') + '#%')
 | |
|         else:
 | |
|             self.tcp.send('MC#' + content + '#' + str(self.myChar) + '#%')
 | |
| 
 | |
|     def onICLogChanged(self):
 | |
|         if self.ICLog.verticalScrollBar().value() == self.ICLog.verticalScrollBar().maximum(): self.ICLog.verticalScrollBar().setValue(self.ICLog.verticalScrollBar().maximum())
 | |
| 
 | |
|     def onOOCLogChanged(self):
 | |
|         if self.OOCLog.verticalScrollBar().value() == self.OOCLog.verticalScrollBar().maximum(): self.OOCLog.verticalScrollBar().setValue(self.OOCLog.verticalScrollBar().maximum())
 | |
|     
 | |
|     def sendOOCchat(self, name, text):
 | |
|         self.tcp.send('CT#' + name + '#' + text + '#%')
 | |
| 
 | |
|     def onOOCReturn(self):
 | |
|         text = encodeAOString(self.OOCInput.text()).replace('\\n', '\n')
 | |
|         if text.startsWith('//'):
 | |
|             code = str(self.OOCInput.text()).replace('//', '', 1).replace('\\NEWLINE', '\n')
 | |
|             try:
 | |
|                 exec code
 | |
|             except Exception as e:
 | |
|                 msg = 'code error\n'
 | |
|                 for arg in e.args:
 | |
|                     msg += str(arg) + '\n'
 | |
| 
 | |
|                 msg = msg.rstrip()
 | |
|                 self.OOCLog.append(msg)
 | |
|                 return
 | |
|             return
 | |
|         elif text.startsWith("/pos "): # why.......
 | |
|             ind = self.boxPositions.findText(str(text.split(" ")[1]))
 | |
|             if ind >= 0: self.boxPositions.setCurrentIndex(ind)
 | |
|             self.OOCInput.clear()
 | |
|             return
 | |
|         
 | |
|         if self.cbMockText.isChecked():
 | |
|             text = mockString(text)
 | |
|         if self.cbAutoCaps.isChecked():
 | |
|             l = QtCore.QStringList(list(text))
 | |
|             l[0] = l[0].toUpper()
 | |
|                 
 | |
|             last = [".", "?", "!", ")", "]"]
 | |
|             if not l[-1] in last:
 | |
|                 l.append(".")
 | |
|             text = l.join("").replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's")
 | |
|         if self.cbSpacing.isChecked():
 | |
|             l = QtCore.QStringList(list(text))
 | |
|             for i in range(1, len(l)+len(l)-1, 2):
 | |
|                 l.insert(i, " ")
 | |
|                 text = l.join("")
 | |
|             
 | |
|         self.sendOOCchat(self.OOCNameInput.text().toUtf8(), text)
 | |
|         self.OOCInput.clear()
 | |
| 
 | |
|     def onICReturn(self):
 | |
|         text = encodeAOString(unicode(self.ICChatInput.text())) #.replace('/n', '\n')
 | |
|         
 | |
|         if text:
 | |
|             if self.cbMockText.isChecked():
 | |
|                 text = mockString(text)
 | |
|             if self.cbAutoCaps.isChecked():
 | |
|                 l = list(text)
 | |
|                 if l[0] == " " and len(l) > 1:
 | |
|                     l[1] = l[1].upper()
 | |
|                 else:
 | |
|                     l[0] = l[0].upper()
 | |
|                 last = [".", "?", "!", "<", ">", ")", "]"]
 | |
|                 if not l[-1] in last:
 | |
|                     l.append(".")
 | |
|                 text = "".join(l).replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's")
 | |
|             if self.cbSpacing.isChecked():
 | |
|                 l = list(text)
 | |
|                 for i in range(1, len(l)+len(l)-1, 2):
 | |
|                     l.insert(i, " ")
 | |
|                     text = "".join(l)
 | |
|         
 | |
|         emote = self.charEmotes[self.selectedEmote]
 | |
|         pre = (emote[1] != "-")
 | |
| 
 | |
|         if self.cbNoInterrupt.isChecked() or not pre:
 | |
|             modifier = 0
 | |
|         else:
 | |
|             modifier = self.playPreanim
 | |
|         objection = 0
 | |
|         if self.btnCustomObjection.isPressed():
 | |
|             objection = 4
 | |
|             self.btnCustomObjection.setPressed(False)
 | |
|         elif self.btnHoldIt.isPressed():
 | |
|             objection = 1
 | |
|             self.btnHoldIt.setPressed(False)
 | |
|         elif self.btnObjection.isPressed():
 | |
|             objection = 2
 | |
|             self.btnObjection.setPressed(False)
 | |
|         elif self.btnTakeThat.isPressed():
 | |
|             objection = 3
 | |
|             self.btnTakeThat.setPressed(False)
 | |
|         if emote[3] == '5': #zoom
 | |
|             if self.cbNoInterrupt.isChecked():
 | |
|                 modifier = 5
 | |
|             else:
 | |
|                 if objection > 0:
 | |
|                     modifier = 6
 | |
|                 else:
 | |
|                     modifier = 5
 | |
|         elif objection > 0:
 | |
|             if self.cbNoInterrupt.isChecked():
 | |
|                 modifier = 0
 | |
|             else:
 | |
|                 modifier = 2
 | |
|         
 | |
|         msg = u"MS#"
 | |
|         
 | |
|         # Visible desk modifier
 | |
|         if "deskmod" in self.features:
 | |
|             if emote[3] == '5': # Zoom forcibly hides the desk
 | |
|                 msg += "0#"
 | |
|             elif len(emote) > 7 and emote[7]: # Respect deskmod if found
 | |
|                 msg += "%s#" % str(emote[7])
 | |
|             else:
 | |
|                 msg += "%d#" % self.cbBench.isChecked()
 | |
|         else:
 | |
|             msg += "chat#"
 | |
| 
 | |
|         msg += emote[1] + "#" #pre-anim
 | |
|         msg += self.charName.title() + "#"
 | |
|         msg += ("" if self.cbFirstPerson.isChecked() else emote[2]) + "#" #anim
 | |
|         msg += text + "#"
 | |
|         msg += (self.lastSide if self.cbFirstPerson.isChecked() else self.charSide) + "#"
 | |
|         
 | |
|         # sfx
 | |
|         if self.boxSounds.currentIndex() > 0:
 | |
|             msg += unicode(self.boxSounds.currentText()) + "#"
 | |
|         elif pre and not self.playPreanim:
 | |
|             msg += "1#"
 | |
|         else:
 | |
|             msg += emote[4] + "#"
 | |
|             
 | |
|         msg += str(modifier) + "#" #emote modifier
 | |
|         msg += str(self.myChar) + "#" #character ID
 | |
|         msg += emote[5] + "#" #sfx delay
 | |
|         msg += str(objection) + "#"
 | |
|         msg += str((self.selectedEvidence + 1) * int(self.present)) + "#" #selected evidence
 | |
|         
 | |
|         if self.present:
 | |
|             self.present = False
 | |
|             self.btnEvidencePresent.setPixmap(self.btnEvidencePresent.button_off)
 | |
|         
 | |
|         if "flipping" in self.features:
 | |
|             msg += str(self.myFlip) + "#"
 | |
|         else:
 | |
|             msg += str(self.myChar) + "#" # old AO servers send a second charID in the message because drunk fanat
 | |
|         
 | |
|         msg += str(int(self.btnRealization.isPressed())) + "#"
 | |
|         msg += str(self.myChatColor) + "#"
 | |
|         
 | |
|         if "cccc_ic_support" in self.features:
 | |
|             showname = self.showname.decode('utf-8')
 | |
|             if self.showname == "" and not self.charShowname == "":
 | |
|                 showname = self.charShowname
 | |
|             msg += showname + "#" # custom showname
 | |
|             if self.cbPair.isChecked():
 | |
|                 msg += str(self.boxPair.currentIndex()) # pair charID
 | |
|                 if "effects" in self.features:
 | |
|                     msg += "^%d#" % self.boxPairOrder.currentIndex() # pair ordering
 | |
|                 else:
 | |
|                     msg += "#"
 | |
|             else:
 | |
|                 msg += "-1#"
 | |
| 
 | |
|             # AO 2.8: always send offset
 | |
|             if "y_offset" in self.features: # AO 2.9
 | |
|                 msg += str(self.sliPairOffset.value()) + "&" + str(-self.sliPairOffsetY.value()) + "#"
 | |
|             else:
 | |
|                 msg += str(self.sliPairOffset.value()) + "#"
 | |
| 
 | |
|             msg += str(int(self.cbNoInterrupt.isChecked())) + "#" # NoInterrupt(TM)
 | |
| 
 | |
|         if "looping_sfx" in self.features: # AO 2.8
 | |
|             msg += emote[6] + "#" # loop sound?
 | |
|             msg += "%d#" % self.btnShake.isPressed() # screen shake
 | |
|             emotes_to_check = [emote[1], "(b)"+emote[2], "(b)/"+emote[2], "(a)"+emote[2], "(a)/"+emote[2] ]
 | |
|             effects_to_check = ["_FrameScreenshake", "_FrameRealization", "_FrameSFX"]
 | |
| 
 | |
|             for f_effect in effects_to_check:
 | |
|                 packet = ""
 | |
|                 for f_emote in emotes_to_check:
 | |
|                     packet += f_emote
 | |
|                     if ini.read_ini_bool("AO2XP.ini", "General", "network frame effects", True):
 | |
|                         sfx_frames = "|".join(ini.read_ini_tags(AOpath + "characters/"+self.charName+"/char.ini", f_emote + f_effect))
 | |
|                         if sfx_frames:
 | |
|                             packet += "|" + sfx_frames
 | |
|                     packet += "^"
 | |
|                 msg += packet + "#"
 | |
| 
 | |
|         if "additive" in self.features:
 | |
|             msg += "%d#" % self.cbAdditive.isChecked()
 | |
| 
 | |
|         if "effects" in self.features:
 | |
|             fx = self.boxEffects.currentText() if self.boxEffects.currentIndex() > 0 else ""
 | |
|             fxSound = ini.get_effect_sound(fx, self.charName)
 | |
|             p_effect = ini.read_ini(AOpath + "characters/"+self.charName+"/char.ini", "options", "effects")
 | |
|             msg += str(fx + "|" + p_effect + "|" + fxSound + "#").encode('utf-8')
 | |
|             self.boxEffects.setCurrentIndex(0)
 | |
|         
 | |
|         self.boxSounds.setCurrentIndex(0)
 | |
|             
 | |
|         # AO 2.10.2+
 | |
|         if "custom_blips" in self.features:
 | |
|             blip = ini.read_ini(AOpath + "characters/"+self.charName+"/char.ini", "options", "blips")
 | |
|             if not blip:
 | |
|                 blip = ini.read_ini(AOpath + "characters/"+self.charName+"/char.ini", "options", "gender")
 | |
|             if blip:
 | |
|                 msg += str(blip) + "#"
 | |
|                 
 | |
|             # Slides
 | |
|             msg += "%d#" % self.cbSlide.isChecked()
 | |
| 
 | |
|         msg += "%"
 | |
|         
 | |
|         self.queueItems.addItem(self.ICChatInput.text())
 | |
|         self.messageQueue.append(msg)
 | |
|         self.lastMessage = msg
 | |
|         
 | |
|         self.ICChatInput.clear()
 | |
|         self.btnRealization.setPressed(False)
 | |
|         self.btnShake.setPressed(False)
 | |
| 
 | |
|     def setBackground(self, bg=None, reset=False):
 | |
|         if bg is None:
 | |
|             bg = self.background
 | |
|         else:
 | |
|             self.background = bg
 | |
|         
 | |
|         if not exists(AOpath + 'background/' + bg):
 | |
|             bg = 'default'
 | |
| 
 | |
|         for bgfile in [["sideDef", "defenseempty"],
 | |
|                        ["benchDef", "defensedesk"],
 | |
|                        ["sidePro", "prosecutorempty"],
 | |
|                        ["benchPro", "prosecutiondesk"],
 | |
|                        ["sideWit", "witnessempty"],
 | |
|                        ["benchWit", "stand"],
 | |
|                        ["sideHld", "helperstand"],
 | |
|                        ["benchHld", "helperdesk"],
 | |
|                        ["sideHlp", "prohelperstand"],
 | |
|                        ["benchHlp", "prohelperdesk"],
 | |
|                        ["sideJud", "judgestand"],
 | |
|                        ["benchJud", "judgedesk"],
 | |
|                        ["sideJur", "jurystand"],
 | |
|                        ["benchJur", "jurydesk"],
 | |
|                        ["sideSea", "seancestand"],
 | |
|                        ["benchSea", "seancedesk"]]:
 | |
| 
 | |
|             bgimg = QtGui.QImage(AOpath + 'background/' + bg + '/' + bgfile[1] + '.png')
 | |
|             if not bgimg.isNull():
 | |
|                 if bgimg.size().width() != self.viewport.width() or bgimg.size().height() != self.viewport.height():
 | |
|                     if "bench" in bgfile[0]:
 | |
|                         _scale = self.viewport.height() / float(bgimg.size().height())
 | |
|                         setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(bgimg.size().width() * _scale, bgimg.size().height() * _scale,  QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)))
 | |
|                     else:
 | |
|                         setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(self.viewport.width(), self.viewport.height(),  QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)))
 | |
|                 else:
 | |
|                     setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg))
 | |
|             else:
 | |
|                 setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg))
 | |
|         
 | |
|         court = AOpath + 'background/' + bg + '/court.png'
 | |
|         self.slideAvailable = exists(court)
 | |
|         
 | |
|         if self.slideAvailable:
 | |
|             slide = QtGui.QPixmap(court)
 | |
|             slide_width = slide.width() * 2
 | |
|             
 | |
|             self.slideBg.resize(slide_width, self.viewport.height()) 
 | |
|             self.slideBg.setPixmap(slide.scaled(slide.width() * 2, self.viewport.height(), QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
| 
 | |
|             courtOverlay = AOpath + 'background/' + bg + '/courtOverlay.png'
 | |
|             if exists(courtOverlay):
 | |
|                 slideOverlay = QtGui.QPixmap(courtOverlay)
 | |
|                 self.slideOverlay.resize(slide_width, self.viewport.height()) 
 | |
|                 self.slideOverlay.setPixmap(slideOverlay.scaled(slide.width() * 2, self.viewport.height(), QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
 | |
|                 self.slideHasOverlay = True
 | |
|             else:
 | |
|                 self.slideHasOverlay = False
 | |
|         
 | |
|         self.bench.show()
 | |
|         
 | |
|         if reset:
 | |
|             self.chatbox.hide()
 | |
|             self.char.hide()
 | |
|             self.setScene(True)
 | |
|     
 | |
|     def startSlide(self, value = [0, 0]):
 | |
|         self.chatbox.hide()
 | |
|         self.presentedEvidence.hide()
 | |
|     
 | |
|         slide_time = 500
 | |
|         self.bench.hide()
 | |
|         self.slideBg.show()
 | |
|         
 | |
|         defPos = QtCore.QRect(0, 0, self.slideBg.width(), self.viewport.height())
 | |
|         proPos = QtCore.QRect(-(defPos.size().width() - self.viewport.width()), 0, defPos.size().width(), self.viewport.height())
 | |
|         witPos = QtCore.QRect(-(self.slideBg.width() / 2 - self.viewport.width() / 2), 0, self.slideBg.width(), self.viewport.height())
 | |
|         
 | |
|         self.slideKind = value[0]
 | |
|         self.slideDirection = value[1]
 | |
|         
 | |
|         # TODO: play only first frame of preanim, figure out zooms
 | |
|         scaling = getScaling(ini.read_ini(AOpath + 'characters/' + self.mChatMessage[CHARNAME] + '/char.ini', "options", "scaling").lower())
 | |
|         if self.mChatMessage[FLIP] == "1":
 | |
|             self.slideSpeaker.setFlipped(True)
 | |
|         else:
 | |
|             self.slideSpeaker.setFlipped(False)
 | |
|             
 | |
|         self.slideSpeaker.playIdle(self.mChatMessage[CHARNAME], self.mChatMessage[ANIM], scaling)
 | |
|         self.slideSpeaker.show()
 | |
|         
 | |
|         if self.slideKind == 0:
 | |
|             if self.slideLastWit:
 | |
|                 self.slideWitness.playIdle(self.slideLastWit[0], self.slideLastWit[1], self.slideLastWit[2])
 | |
|                 self.slideWitness.show()
 | |
|             if self.slideDirection == 0:
 | |
|                 bg_start = defPos
 | |
|                 bg_end = proPos
 | |
|             else:
 | |
|                 bg_start = proPos
 | |
|                 bg_end = defPos
 | |
|         elif self.slideKind == 1:
 | |
|             if self.slideDirection == 0:
 | |
|                 bg_start = defPos
 | |
|                 bg_end = witPos
 | |
|             else:
 | |
|                 bg_start = witPos
 | |
|                 bg_end = defPos
 | |
|         elif self.slideKind == 2:
 | |
|             if self.slideDirection == 0:
 | |
|                 bg_start = witPos
 | |
|                 bg_end = proPos
 | |
|             else:
 | |
|                 bg_start = proPos
 | |
|                 bg_end = witPos
 | |
|         
 | |
|         self.slideBg.setGeometry(bg_start)
 | |
|         self.slideBgAnimation.setStartValue(bg_start)
 | |
|         self.slideBgAnimation.setEndValue(bg_end)
 | |
|         self.slideBgAnimation.setDuration(slide_time)
 | |
|         self.slideBgAnimation.setEasingCurve(QtCore.QEasingCurve.InOutQuad)
 | |
|         self.slideBgAnimation.start()
 | |
| 
 | |
|         if self.slideHasOverlay:
 | |
|             self.slideOverlay.show()
 | |
|             self.slideOverlay.setGeometry(bg_start)
 | |
|     
 | |
|     def slideChanged(self):
 | |
|         x = self.slideBg.x()
 | |
|         self.slideOverlay.move(x, 0)
 | |
|         
 | |
|         # def-pro
 | |
|         if self.slideKind == 0:
 | |
|             if self.slideLastWit:
 | |
|                 self.slideWitness.moveSlide(x + self.slideBg.width() / 2 - self.viewport.width() / 2)
 | |
|             if self.slideDirection == 0:
 | |
|                 self.char.moveSlide(x)
 | |
|                 self.slideSpeaker.moveSlide(x + self.slideBg.width() - self.viewport.width())
 | |
|             else:
 | |
|                 self.char.moveSlide(x + self.slideBg.width() - self.viewport.width())
 | |
|                 self.slideSpeaker.moveSlide(x)
 | |
|         # def-wit
 | |
|         elif self.slideKind == 1:
 | |
|             if self.slideDirection == 0:
 | |
|                 self.char.moveSlide(x)
 | |
|                 self.slideSpeaker.moveSlide(x + self.slideBg.width() / 2 - self.viewport.width() / 2)
 | |
|             else:
 | |
|                 self.char.moveSlide(x + self.slideBg.width() / 2 - self.viewport.width() / 2)
 | |
|                 self.slideSpeaker.moveSlide(x)
 | |
|         # pro-wit
 | |
|         elif self.slideKind == 2:
 | |
|             if self.slideDirection == 0:
 | |
|                 self.char.moveSlide(x + self.slideBg.width() / 2 - self.viewport.width() / 2)
 | |
|                 self.slideSpeaker.moveSlide(x + self.slideBg.width() - self.viewport.width())
 | |
|             else:
 | |
|                 self.char.moveSlide(x + self.slideBg.width() - self.viewport.width())
 | |
|                 self.slideSpeaker.moveSlide(x + self.slideBg.width() / 2 - self.viewport.width() / 2)
 | |
|         
 | |
|     def slideDone(self):
 | |
|         self.slideBg.hide()
 | |
|         self.slideOverlay.hide()
 | |
|         self.slideWitness.hide()
 | |
|         self.slideSpeaker.hide()
 | |
|         self.handleChatMessage2()
 | |
| 
 | |
|     def netmsgHP(self, type, health):
 | |
|         if type == 1:
 | |
|             self.btnDefenseBar.setHealth(health)
 | |
|         elif type == 2:
 | |
|             self.btnProsecutionBar.setHealth(health)
 | |
|     
 | |
|     def netmsgMS(self, p_contents):
 | |
|         if len(p_contents) < 15: #this is already done on the TCP thread but i'll do it here anyway as well
 | |
|             return
 | |
|         
 | |
|         AO2chat = "cccc_ic_support" in self.features
 | |
| 
 | |
|         if int(p_contents[CHAR_ID]) in self.muted: # skip the self.chatmessage copy line below
 | |
|             return
 | |
|             
 | |
|         mChatMessage = {}
 | |
| 
 | |
|         for n_string in range(self.chatMessageSize):
 | |
|             if n_string < len(p_contents) and (n_string < 16 or AO2chat):
 | |
|                 mChatMessage[n_string] = p_contents[n_string]
 | |
|             else:
 | |
|                 mChatMessage[n_string] = ""
 | |
|          
 | |
|         # For debugging
 | |
|         # print mChatMessage
 | |
| 
 | |
|         fCharId = int(mChatMessage[CHAR_ID])
 | |
|         
 | |
|         if fCharId < 0 or fCharId >= len(self.charList):
 | |
|             return
 | |
|         
 | |
|         fShowname = ""
 | |
|         if not mChatMessage[SHOWNAME]:
 | |
|             fShowname = mChatMessage[CHARNAME]
 | |
|         else:
 | |
|             fShowname = mChatMessage[SHOWNAME]
 | |
|         
 | |
|         if self.messageQueue:
 | |
|             chatMsgComp = decodeAOString(self.messageQueue[0].split('#')[5]).strip()
 | |
|             examine = chatMsgComp == ">" or chatMsgComp == "<" or chatMsgComp == "="
 | |
|             special = not chatMsgComp
 | |
|             if examine or (fCharId == self.myChar and (special or mChatMessage[CHATMSG] == chatMsgComp)): # our message showed up
 | |
|                 del self.messageQueue[0]
 | |
|                 self.queueItems.takeItem(0)
 | |
|                 if self.cbAdditive.isChecked():
 | |
|                     self.ICChatInput.insert(" ")
 | |
|         
 | |
|         mChatMessage[CHARNAME] = mChatMessage[CHARNAME].decode("utf-8")
 | |
|         mChatMessage[OTHER_NAME] = mChatMessage[OTHER_NAME].decode("utf-8")
 | |
|         mChatMessage[SHOWNAME] = mChatMessage[SHOWNAME].decode('utf-8')
 | |
|         
 | |
|         fChar = mChatMessage[CHARNAME]
 | |
|         evidence = int(mChatMessage[EVIDENCE]) - 1
 | |
|         
 | |
|         # Some characters use " - " instead of "-" for no preanim.
 | |
|         mChatMessage[PREANIM] = mChatMessage[PREANIM].strip()
 | |
|         
 | |
|         customObjection = "custom"
 | |
|         try: 
 | |
|             objectionMod = int(mChatMessage[SHOUT_MOD])
 | |
|         except:
 | |
|             if "4&" in mChatMessage[SHOUT_MOD]: # custom objection name
 | |
|                 objectionMod = 4
 | |
|                 customObjection = mChatMessage[SHOUT_MOD].split("4&")[1] # get the name
 | |
|             else: # just in case of mindfuckery
 | |
|                 objectionMod = 0
 | |
|         
 | |
|         # TODO: Make logging format customizable
 | |
|         t = time.localtime()
 | |
|         logcharName = fChar
 | |
|         
 | |
|         timestamp = "[%d:%.2d] " % (t[3], t[4]) if not self.demoPlaying else ""
 | |
|         
 | |
|         if fChar.lower() != self.charList[fCharId][0].lower():
 | |
|             logcharName = self.charList[fCharId][0] + ' (' + fChar + ')'
 | |
|         
 | |
|         chatmsg = mChatMessage[CHATMSG].strip()
 | |
|         
 | |
|         # Callwords
 | |
|         mentioned = False
 | |
|         if exists(AO2XPpath + "callwords.ini"):
 | |
|             with open(AO2XPpath + "callwords.ini") as f: 
 | |
|                 callwords = [line.rstrip() for line in f]
 | |
|                 for callword in callwords:
 | |
|                     if callword.decode('utf-8').lower() in chatmsg.lower().split(" "):
 | |
|                         self.OOCLog.append("<b>%s called you.</b>" % fChar)
 | |
|                         QtGui.QApplication.alert(self, 1000)
 | |
|                         snd = audio.loadHandle(False, "word_call.wav", 0, 0, BASS_STREAM_AUTOFREE)
 | |
|                         if snd:
 | |
|                             audio.playHandle(snd, True)
 | |
|                         mentioned = True
 | |
|                         break
 | |
|         
 | |
|         if mChatMessage[SHOWNAME] and mChatMessage[SHOWNAME].lower() != fChar.lower():
 | |
|             try:
 | |
|                 logcharName += " (" + mChatMessage[SHOWNAME]+")"
 | |
|             except:
 | |
|                 logcharName += " (???)"
 | |
|                 
 | |
|         if objectionMod == 1:
 | |
|             self.ICLog.append(timestamp + '%s: %s' % (logcharName, "<b>Hold it!</b>"))
 | |
|         elif objectionMod == 2 or objectionMod == 4:
 | |
|             self.ICLog.append(timestamp + '%s: %s' % (logcharName, "<b>Objection!</b>"))
 | |
|         elif objectionMod == 3:
 | |
|             self.ICLog.append(timestamp + '%s: %s' % (logcharName, "<b>Take that!</b>"))
 | |
|         
 | |
|         if evidence == -1:
 | |
|             if chatmsg:
 | |
|                 self.ICLog.append(timestamp + '%s%s: %s%s' % (
 | |
|                     "<b>" if mentioned else "",
 | |
|                     logcharName,
 | |
|                     chatmsg.replace("<", "<"),
 | |
|                     "</b>" if mentioned else ""
 | |
|                     ))
 | |
|         else:
 | |
|             eviname = '(NULL) %d' % evidence
 | |
|             try:
 | |
|                 eviname = self.evidence[evidence][0]
 | |
|             except:
 | |
|                 pass
 | |
|             
 | |
|             if chatmsg:
 | |
|                 self.ICLog.append(timestamp + '%s%s: %s%s\n%s presented an evidence: %s' % (
 | |
|                     "<b>" if mentioned else "",
 | |
|                     logcharName,
 | |
|                     chatmsg.replace("<", "<"),
 | |
|                     "</b>" if mentioned else "",
 | |
|                     fChar,
 | |
|                     eviname.strip()
 | |
|                     ))
 | |
|             else:
 | |
|                 self.ICLog.append(timestamp + '%s presented an evidence: %s' % (fChar, eviname.strip()))
 | |
| 
 | |
|         self.isAdditive = (mChatMessage[ADDITIVE] == "1")
 | |
|         
 | |
|         if objectionMod <= 4 and objectionMod >= 1:
 | |
|             # Skip everything in the queue, show message immediately
 | |
|             self.inboxQueue = []
 | |
|             self.inboxQueue.append(mChatMessage)
 | |
|             self.inboxTimer.stop()
 | |
|             self.chatTickTimer.stop()
 | |
|             self.mChatMessage = mChatMessage
 | |
|             
 | |
|             objections = ["holdit", "objection", "takethat", "custom_objections/"+customObjection if customObjection != "custom" else "custom"]
 | |
|             self.objectionView.stop()
 | |
|             self.objectionView.play(objections[objectionMod - 1], fChar.lower())
 | |
|             self.presentedEvidence.hide()
 | |
|             self.playObjectionSound(fChar.lower(), objectionMod)
 | |
|             
 | |
|             emoteMod = int(self.mChatMessage[EMOTE_MOD])
 | |
|             if emoteMod == 0:
 | |
|                 self.mChatMessage[EMOTE_MOD] = 1
 | |
|         else:
 | |
|             # Old behavior
 | |
|             #self.mChatMessage = mChatMessage
 | |
|             #self.handleChatMessage2()
 | |
|             
 | |
|             # Add message to queue and wait, unless queue empty
 | |
|             self.inboxQueue.append(mChatMessage)
 | |
|             if len(self.inboxQueue) == 1:
 | |
|                 self.handleChatMessage1(mChatMessage)
 | |
|     
 | |
|     def setTextColor(self):
 | |
|         textColor = int(self.mChatMessage[TEXT_COLOR])
 | |
|         
 | |
|         isRainbow = textColor == C_RAINBOW
 | |
|         
 | |
|         if textColor == 0:
 | |
|             color = QtGui.QColor(255, 255, 255)
 | |
|         elif textColor == 1:
 | |
|             color = QtGui.QColor(0, 255, 0)
 | |
|         elif textColor == 2:
 | |
|             color = QtGui.QColor(255, 0, 0)
 | |
|         elif textColor == 3:
 | |
|             color = QtGui.QColor(255, 165, 0)
 | |
|         elif textColor == 4:
 | |
|             color = QtGui.QColor(45, 150, 255)
 | |
|         elif textColor == 5:
 | |
|             color = QtGui.QColor(255, 255, 0)
 | |
|         elif textColor == 6:
 | |
|             color = QtGui.QColor(255, 192, 203)
 | |
|         elif textColor == 7:
 | |
|             color = QtGui.QColor(0, 255, 255)
 | |
|         elif textColor == 8:
 | |
|             color = QtGui.QColor(200, 200, 200)
 | |
|         elif textColor == 10:
 | |
|             color = QtGui.QColor(0, 0, 0)
 | |
|         else:
 | |
|             color = QtGui.QColor(255, 255, 255)
 | |
|         
 | |
|         if isRainbow:
 | |
|             self.text.show()
 | |
|             self.ao2text.hide()
 | |
|         else:
 | |
|             self.text.hide()
 | |
|             self.ao2text.show()
 | |
|         
 | |
|         style = "background-color: rgba(0, 0, 0, 0);\n"
 | |
|         style += "color: rgb(" + str(color.red()) + ", " + str(color.green()) + ", " + str(color.blue()) + ")"
 | |
|         self.ao2text.setStyleSheet(style)
 | |
|     
 | |
|     def setScene(self, init=False):
 | |
|         if not init:
 | |
|             if self.animIsEmpty:
 | |
|                 return
 | |
|             side = self.mChatMessage[SIDE]
 | |
|             self.lastSide = side
 | |
|             # TODO: support custom positions
 | |
|             if side not in self.defaultPositions:
 | |
|                 side = 'wit'
 | |
|         else:
 | |
|             side = 'wit'
 | |
|         
 | |
|         self.presentedEvidence.hide()
 | |
|         
 | |
|         if side == 'def':
 | |
|             self.court.setPixmap(self.sideDef)
 | |
|             self.bench.setPixmap(self.benchDef)
 | |
|             self.bench.move(0, self.viewport.height() - self.benchDef.size().height())
 | |
|         elif side == 'pro':
 | |
|             self.court.setPixmap(self.sidePro)
 | |
|             self.bench.setPixmap(self.benchPro)
 | |
|             self.bench.move(self.viewport.width() - self.benchPro.size().width(), self.viewport.height() - self.benchPro.size().height())
 | |
|         elif side == 'wit':
 | |
|             self.court.setPixmap(self.sideWit)
 | |
|             self.bench.setPixmap(self.benchWit)
 | |
|             self.bench.move(self.viewport.width() / 2 - self.benchPro.size().width() / 2, 0)
 | |
|         elif side == 'hld':
 | |
|             self.court.setPixmap(self.sideHld)
 | |
|             self.bench.setPixmap(self.benchHld)
 | |
|         elif side == 'hlp':
 | |
|             self.court.setPixmap(self.sideHlp)
 | |
|             self.bench.setPixmap(self.benchHlp)
 | |
|         elif side == 'jud':
 | |
|             self.court.setPixmap(self.sideJud)
 | |
|             self.bench.setPixmap(self.benchJud)
 | |
|             self.bench.move(self.viewport.width() / 2 - self.benchJud.size().width() / 2, 0)
 | |
|         elif side == 'sea':
 | |
|             bench = self.benchJud if self.benchSea.isNull() else self.benchSea
 | |
|             self.court.setPixmap(self.sideJud if self.sideSea.isNull() else self.sideSea)
 | |
|             self.bench.setPixmap(bench)
 | |
|             self.bench.move(self.viewport.width() / 2 - bench.size().width() / 2, 0)
 | |
|         elif side == 'jur':
 | |
|             bench = self.benchJud if self.benchJur.isNull() else self.benchJur
 | |
|             self.court.setPixmap(self.sideJud if self.sideJur.isNull() else self.sideJur)
 | |
|             self.bench.setPixmap(bench)
 | |
|             self.bench.move(self.viewport.width() / 2 - bench.size().width() / 2, 0)
 | |
| 
 | |
|     def setBench(self, isPreanim = False):
 | |
|         if self.animIsEmpty:
 | |
|             return
 | |
|             
 | |
|         deskmod = self.mChatMessage[DESK_MOD]
 | |
|         
 | |
|         if deskmod == "0" or (deskmod == "chat" and side in ("jud", "hld", "hlp")):
 | |
|             self.bench.hide()
 | |
|         elif deskmod == "1" or (deskmod == "chat" and side in ("def", "pro", "wit")):
 | |
|             self.bench.show()
 | |
|         elif deskmod == "2" or deskmod == "4":
 | |
|             if isPreanim:
 | |
|                 self.bench.hide()
 | |
|             else:
 | |
|                 self.bench.show()
 | |
|         elif deskmod == "3" or deskmod == "5":
 | |
|             if isPreanim:
 | |
|                 self.bench.show()
 | |
|             else:
 | |
|                 self.bench.hide()
 | |
|         else:
 | |
|             self.bench.hide()
 | |
| 
 | |
|     def objectionDone(self):
 | |
|         self.handleChatMessage1()
 | |
|         
 | |
|     def handleChatMessage1(self, mChatMessage = None):
 | |
|         if not self.slideEnabled:
 | |
|             if mChatMessage:
 | |
|                 self.mChatMessage = mChatMessage
 | |
|             self.handleChatMessage2()
 | |
|             return
 | |
|             
 | |
|         wasZoom = self.mChatMessage[EMOTE_MOD] and int(self.mChatMessage[EMOTE_MOD]) >= 5
 | |
|     
 | |
|         if mChatMessage:
 | |
|             self.mChatMessage = mChatMessage
 | |
|         
 | |
|         newSide = self.mChatMessage[SIDE]
 | |
|         canSlide = self.slideAvailable and not wasZoom and int(self.mChatMessage[EMOTE_MOD]) < 5 and self.mChatMessage[ANIM].strip() != ""
 | |
|         
 | |
|         if canSlide and self.mChatMessage[SLIDE] == "1" and self.slideLastPos and newSide != self.slideLastPos and newSide in ["def", "pro", "wit"]:
 | |
|             self.startSlide(self.slideMap[self.slideLastPos][newSide])
 | |
|         else:
 | |
|             self.handleChatMessage2()
 | |
| 
 | |
|     def handleChatMessage2(self):
 | |
|         self.zoom.setZoom(False)
 | |
|         self.effectView.stop()
 | |
|         
 | |
|         self.textState = 0
 | |
|         self.animState = 0
 | |
|         self.objectionView.stop()
 | |
|         self.chatTickTimer.stop()
 | |
|         self.presentedEvidence.hide()
 | |
|         
 | |
|         self.chatMessageIsEmpty = self.mChatMessage[CHATMSG].strip() == ""
 | |
|         self.animIsEmpty = self.mChatMessage[ANIM].strip() == ""
 | |
|         
 | |
|         if not self.animIsEmpty:
 | |
|             self.char.stop()
 | |
| 
 | |
|         if not self.mChatMessage[SHOWNAME]:
 | |
|             self.name.setText(self.mChatMessage[CHARNAME])
 | |
|         else:
 | |
|             self.name.setText(self.mChatMessage[SHOWNAME])
 | |
| 
 | |
|         self.chatbox.hide()
 | |
| 
 | |
|         self.setScene()
 | |
|         self.setTextColor()
 | |
|         
 | |
|         fMessage = self.mChatMessage[CHATMSG]
 | |
|         if len(fMessage) >= 2:
 | |
|             self.messageIsCentered = fMessage.startswith("~~")
 | |
|         else:
 | |
|             self.ao2text.setAlignment(QtCore.Qt.AlignLeft)
 | |
|             self.text.setAlignment(QtCore.Qt.AlignLeft)
 | |
|         
 | |
|         if not self.animIsEmpty:
 | |
|             if self.mChatMessage[FLIP] == "1":
 | |
|                 self.char.setFlipped(True)
 | |
|             else:
 | |
|                 self.char.setFlipped(False)
 | |
|         
 | |
|         side = self.mChatMessage[SIDE]
 | |
|         emoteMod = int(self.mChatMessage[EMOTE_MOD])
 | |
| 
 | |
|         # AO 2.8: always offset player
 | |
|         hor_offset = vert_offset = 0
 | |
| 
 | |
|         if "y_offset" in self.features: # AO 2.9
 | |
|             keyword = "<and>" if "<and>" in self.mChatMessage[SELF_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
 | |
|             offset = self.mChatMessage[SELF_OFFSET].split(keyword)
 | |
|             hor_offset = int(offset[0]) if offset[0] else 0
 | |
|             vert_offset = int(offset[1]) if len(offset) > 1 else 0
 | |
|         else:
 | |
|             hor_offset = int(self.mChatMessage[SELF_OFFSET])
 | |
|         
 | |
|         if side == "def":
 | |
|             if hor_offset > 0 and vert_offset == 0:
 | |
|                 vert_offset = hor_offset / 10
 | |
|         elif side == "pro":
 | |
|             if hor_offset < 0 and vert_offset == 0:
 | |
|                 vert_offset = -1 * hor_offset / 10
 | |
| 
 | |
|         if not self.animIsEmpty:
 | |
|             self.char.move(self.viewport.width() * hor_offset / 100, self.viewport.height() * vert_offset / 100)
 | |
| 
 | |
|         # check if paired
 | |
|         if not self.mChatMessage[OTHER_CHARID] and not self.animIsEmpty:
 | |
|             self.sideChar.hide()
 | |
|             self.sideChar.move(0,0)
 | |
|         else:
 | |
|             if "effects" in self.features:
 | |
|                 got_otherCharId = int(self.mChatMessage[OTHER_CHARID].split("^")[0])
 | |
|             else:
 | |
|                 got_otherCharId = int(self.mChatMessage[OTHER_CHARID])
 | |
| 
 | |
|             if got_otherCharId > -1: # user is paired
 | |
|                 self.sideChar.show()
 | |
|                 
 | |
|                 boxPairOrder = self.mChatMessage[OTHER_CHARID].split("^")
 | |
|                 if "effects" in self.features and len(boxPairOrder) > 1:   
 | |
|                     boxPairOrder = int(boxPairOrder[1])
 | |
|                 else:    
 | |
|                     boxPairOrder = -1
 | |
| 
 | |
|                 hor2_offset = vert2_offset = 0
 | |
|                 if "y_offset" in self.features: # AO 2.9
 | |
|                     keyword = "<and>" if "<and>" in self.mChatMessage[OTHER_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
 | |
|                     hor2_offset = int(self.mChatMessage[OTHER_OFFSET].split(keyword)[0])
 | |
|                     vert2_offset = int(self.mChatMessage[OTHER_OFFSET].split(keyword)[1]) if len(self.mChatMessage[OTHER_OFFSET].split(keyword)) > 1 else 0
 | |
|                 else:
 | |
|                     hor2_offset = int(self.mChatMessage[OTHER_OFFSET])
 | |
| 
 | |
|                 if side == "def":
 | |
|                     if hor2_offset > 0:
 | |
|                         vert2_offset = hor2_offset / 10
 | |
| 
 | |
|                 elif side == "pro":
 | |
|                     if hor2_offset < 0:
 | |
|                         vert2_offset = -1 * hor2_offset / 10
 | |
| 
 | |
|                 if boxPairOrder == -1: # pair ordering not supported
 | |
|                     if hor2_offset >= hor_offset:
 | |
|                         self.sideChar.raise_()
 | |
|                         self.char.raise_()
 | |
|                     else:
 | |
|                         self.char.raise_()
 | |
|                         self.sideChar.raise_()
 | |
|                 elif boxPairOrder == 0: # front
 | |
|                     self.sideChar.raise_()
 | |
|                     self.char.raise_()
 | |
|                 elif boxPairOrder == 1: # behind
 | |
|                     self.char.raise_()
 | |
|                     self.sideChar.raise_()
 | |
| 
 | |
|                 self.sideChar.move(self.viewport.width() * hor2_offset / 100, self.viewport.height() * vert2_offset / 100)
 | |
| 
 | |
|                 self.bench.raise_()
 | |
|                 self.chatbox.raise_()
 | |
|                 self.effectView.raise_()
 | |
|                 self.objectionView.raise_()
 | |
|                 self.whiteFlashLabel.raise_()
 | |
|                 
 | |
|                 self.scaling[1] = getScaling(ini.read_ini(AOpath + 'characters/' + self.mChatMessage[OTHER_NAME] + '/char.ini', "options", "scaling").lower())
 | |
| 
 | |
|                 self.sideChar.setFlipped(self.mChatMessage[OTHER_FLIP] == "1")
 | |
|                 if not self.animIsEmpty:
 | |
|                     self.sideChar.playIdle(self.mChatMessage[OTHER_NAME], self.mChatMessage[OTHER_EMOTE], self.scaling[1])
 | |
|             
 | |
|             elif not self.animIsEmpty:
 | |
|                 self.sideChar.hide()
 | |
|                 self.sideChar.move(0, 0)
 | |
|         
 | |
|         self.scaling[0] = getScaling(ini.read_ini(AOpath + 'characters/' + self.mChatMessage[CHARNAME] + '/char.ini', "options", "scaling").lower())
 | |
|         
 | |
|         if self.slideEnabled and self.slideAvailable:
 | |
|             if side == "wit":
 | |
|                 if int(self.mChatMessage[EMOTE_MOD]) < 5: # Don't save anim if zoom
 | |
|                     self.slideLastWit = [
 | |
|                         self.mChatMessage[CHARNAME],
 | |
|                         self.mChatMessage[ANIM],
 | |
|                         self.scaling[0]
 | |
|                         ]
 | |
|                 self.slideLastPos = "wit"
 | |
|             elif side == "def" or side == "pro":
 | |
|                 self.slideLastPos = side
 | |
|             else:
 | |
|                 self.slideLastPos = None
 | |
| 
 | |
|         if (emoteMod == PRE or emoteMod == PRE_SHOUT or emoteMod == NOPRE_ZOOM_SHOUT):
 | |
|             self.setBench(True)
 | |
|             self.playPre(False)
 | |
|         elif emoteMod == NOPRE or emoteMod == NOPRE_ZOOM:
 | |
|             if self.mChatMessage[NO_INTERRUPT] == "0":
 | |
|                 if self.mChatMessage[SFX] not in ["0", "1"]:
 | |
|                     self.playSfx()
 | |
|                 self.handleChatMessage3()
 | |
|             else:
 | |
|                 self.playPre(True)
 | |
|             
 | |
|     def playPre(self, nonInterrupting):
 | |
|         fChar = self.mChatMessage[CHARNAME].lower()
 | |
|         fPreanim = self.mChatMessage[PREANIM].strip()
 | |
|         
 | |
|         ao2Duration = ini.read_ini_int(AOpath + "characters/" + fChar + "/char.ini", "time", fPreanim, -1)
 | |
|         textDelay = ini.read_ini_int(AOpath + "characters/" + fChar + "/char.ini", "textdelay", fPreanim, -1)
 | |
|         sfxDelay = int(self.mChatMessage[SFX_DELAY]) * 60
 | |
|         
 | |
|         if sfxDelay > 0:
 | |
|             self.sfxDelayTimer.start(sfxDelay)
 | |
|         else:
 | |
|             self.playSfx()
 | |
|         
 | |
|         preanimDuration = ao2Duration
 | |
|             
 | |
|         animToFind = AOpath + "characters/" + fChar + "/" + fPreanim + ".gif"
 | |
|         apngToFind = AOpath + "characters/" + fChar + "/" + fPreanim + ".apng"
 | |
|         webpToFind = AOpath + "characters/" + fChar + "/" + fPreanim + ".webp"
 | |
|         
 | |
|         if (not animToFind and not apngToFind and not webpToFind) or preanimDuration < 0:
 | |
|             if nonInterrupting:
 | |
|                 self.animState = 4
 | |
|             else:
 | |
|                 self.animState = 1
 | |
|             self.preanimDone()
 | |
|             return
 | |
|         
 | |
|         self.char.playPre(fChar, fPreanim, preanimDuration, self.scaling[0])
 | |
|         if nonInterrupting:
 | |
|             self.animState = 4
 | |
|         else:
 | |
|             self.animState = 1
 | |
|         
 | |
|         if textDelay >= 0:
 | |
|             pass # TODO: text delay timer, but not now.
 | |
|         
 | |
|         if nonInterrupting:
 | |
|             self.handleChatMessage3()
 | |
|         
 | |
|     def preanimDone(self):
 | |
|         self.animState = 1
 | |
|         self.handleChatMessage3()
 | |
|     
 | |
|     def handleChatMessage3(self):
 | |
|         self.startChatTicking()
 | |
|         self.setBench(False)
 | |
|         
 | |
|         fEvidenceId = int(self.mChatMessage[EVIDENCE])
 | |
|         fSide = self.mChatMessage[SIDE]
 | |
|         
 | |
|         emoteMod = int(self.mChatMessage[EMOTE_MOD])
 | |
|         
 | |
|         if fEvidenceId > 0 and fEvidenceId <= len(self.evidence):
 | |
|             fImage = self.evidence[fEvidenceId-1][2]
 | |
|             isLeftSide = not (fSide == "def" or fSide == "hlp" or fSide == "jud" or fSide == "jur")
 | |
|             
 | |
|             self.setEvidenceImage(self.presentedEvidence, fImage, True)
 | |
|             self.playSound("sfx-evidenceshoop.opus")
 | |
|             
 | |
|             if not isLeftSide:
 | |
|                 self.presentedEvidence.move(self.viewport.x() + 170 * self.viewportScale, self.viewport.y() + 16 * self.viewportScale)
 | |
|             else:
 | |
|                 self.presentedEvidence.move(self.viewport.x() + 16 * self.viewportScale,  self.viewport.y() + 16 * self.viewportScale)
 | |
|             self.presentedEvidence.show()
 | |
|         else:
 | |
|             self.presentedEvidence.hide()
 | |
|         
 | |
|         side = self.mChatMessage[SIDE]
 | |
|         if emoteMod == 5 or emoteMod == 6:
 | |
|             self.bench.hide()
 | |
|             self.sideChar.hide()
 | |
|             self.char.move(0,0)
 | |
|             
 | |
|             if side == "pro" or side == "hlp" or side == "wit":
 | |
|                 self.zoom.setZoom(True, 1)
 | |
|             else:
 | |
|                 self.zoom.setZoom(True, 0)
 | |
|         
 | |
|         f_animState = 0
 | |
|         text_is_blue = int(self.mChatMessage[TEXT_COLOR]) == 4
 | |
|         
 | |
|         if not text_is_blue and self.textState == 1:
 | |
|             f_animState = 2
 | |
|             self.entireMessageIsBlue = False
 | |
|         else:
 | |
|             f_animState = 3
 | |
|             self.entireMessageIsBlue = True
 | |
|         
 | |
|         if f_animState <= self.animState:
 | |
|             return
 | |
|             
 | |
|         fChar = self.mChatMessage[CHARNAME]
 | |
|         f_emote = self.mChatMessage[ANIM]
 | |
|         
 | |
|         if not self.animIsEmpty:
 | |
|             self.char.stop()
 | |
|         
 | |
|             if f_animState == 2:
 | |
|                 self.char.playTalking(fChar, f_emote, self.scaling[0])
 | |
|                 self.animState = 2
 | |
|             else:
 | |
|                 self.char.playIdle(fChar, f_emote, self.scaling[0])
 | |
|                 self.animState = 3
 | |
| 
 | |
|     def playEffect(self, fxName, fxSound, pChar, pFolder):
 | |
|         effect = ini.get_effect(fxName, pChar, pFolder)
 | |
|         if not effect: return
 | |
| 
 | |
|         if fxSound:
 | |
|             self.playSound(fxSound)
 | |
| 
 | |
|         if "effects" not in self.features: return
 | |
| 
 | |
|         self.effectView.setPlayOnce(True)
 | |
|         self.effectView.play(effect)
 | |
| 
 | |
|     def startChatTicking(self):
 | |
|         if self.textState != 0:
 | |
|             return
 | |
| 
 | |
|         if self.mChatMessage[EFFECTS]:
 | |
|             fxList = self.mChatMessage[EFFECTS].split("|")
 | |
|             fx = fxList[0]
 | |
|             fxSound = ""
 | |
|             fxFolder = ""
 | |
| 
 | |
|             if len(fxList) > 1:
 | |
|                 fxSound = fxList[1]
 | |
|             if len(fxList) > 2:
 | |
|                 fxFolder = fxList[1]
 | |
|                 fxSound = fxList[2]
 | |
| 
 | |
|             if fx and fx not in ("-", "None"):
 | |
|                 self.playEffect(fx, fxSound, self.mChatMessage[CHARNAME], fxFolder)
 | |
| 
 | |
|         elif self.mChatMessage[REALIZATION] == "1":
 | |
|             self.setWhiteFlash(True, 1, 125)
 | |
|         
 | |
|         self.setTextColor()
 | |
| 
 | |
|         charid = int(self.mChatMessage[CHAR_ID])
 | |
|         if not self.isAdditive or self.additiveChar != charid:
 | |
|             self.ao2text.clear()
 | |
|             self.text.setText("")
 | |
|             self.additiveChar = charid
 | |
| 
 | |
|         if self.chatMessageIsEmpty:
 | |
|             self.textState = 2
 | |
|             self.inboxTimer.start(self.textWaitTime)
 | |
|             return
 | |
|         
 | |
|         self.inlineColorStack = []
 | |
|         
 | |
|         self.chatbox.show()
 | |
| 
 | |
|         self.tickPos = 0
 | |
|         self.blipPos = 0
 | |
|         self.inlineBlueDepth = 0
 | |
|         
 | |
|         self.currentDisplaySpeed = 3
 | |
|         self.chatTickTimer.start(self.messageDisplaySpeed[self.currentDisplaySpeed])
 | |
| 
 | |
|         self.blip = self.mChatMessage[BLIPS].lower()
 | |
|         
 | |
|         if not self.blip:
 | |
|             self.blip = self.charList[charid][2].lower()
 | |
|             if not self.blip:
 | |
|                 self.blip = "male"
 | |
| 
 | |
|         path = testPath(
 | |
|             AOpath + "sounds/blips/"+ self.blip +".wav",
 | |
|             AOpath + "sounds/blips/"+ self.blip +".opus",
 | |
|             AOpath + "sounds/general/sfx-blip"+ self.blip +".wav",
 | |
|             AOpath + "sounds/general/sfx-blip"+ self.blip +".opus"
 | |
|         )
 | |
|         
 | |
|         if path:
 | |
|             if self.blipSound:
 | |
|                 audio.freeHandle(self.blipSound)
 | |
|             self.blipSound = audio.loadHandle(False, path, 0, 0, 0)
 | |
| 
 | |
|             if self.blipSound:
 | |
|                 audio.setHandleAttr(self.blipSound, BASS_ATTRIB_VOL, self.sliBlipsVolume.value() / 100.0)
 | |
| 
 | |
|         emoteMod = int(self.mChatMessage[EMOTE_MOD])
 | |
|         if emoteMod in (0, 5) and self.mChatMessage[SCREENSHAKE] == "1":
 | |
|             self.setScreenShake(True)
 | |
| 
 | |
|         self.textState = 1
 | |
|     
 | |
|     def chatTick(self):
 | |
|         fMessage = self.mChatMessage[CHATMSG]
 | |
|         
 | |
|         self.chatTickTimer.stop()
 | |
|         formattingChar = False
 | |
|         
 | |
|         if self.messageIsCentered:
 | |
|             fMessage = fMessage.strip("~~")
 | |
|         
 | |
|         if self.tickPos >= len(fMessage):
 | |
|             self.textState = 2
 | |
|             if self.animState != 4:
 | |
|                 self.animState = 3
 | |
|                 if not self.animIsEmpty:
 | |
|                     self.char.playIdle(self.mChatMessage[CHARNAME], self.mChatMessage[ANIM], self.scaling[0])
 | |
|             self.inboxTimer.start(self.textWaitTime)
 | |
|             
 | |
|         else:
 | |
|             fCharacter2 = fMessage[self.tickPos]
 | |
|             fCharacter = QtCore.QString(fCharacter2)
 | |
| 
 | |
|             if fCharacter in [" ", "\n", "<", ">"]:
 | |
|                 self.text.insertPlainText(fCharacter)
 | |
|                 self.ao2text.insertPlainText(fCharacter)
 | |
|             
 | |
|             elif fCharacter == "\r":
 | |
|                 self.text.insertPlainText("\n")
 | |
|                 self.ao2text.insertPlainText("\n")
 | |
|             
 | |
|             elif fCharacter == "\\" and not self.nextCharacterIsNotSpecial:
 | |
|                 self.nextCharacterIsNotSpecial = True
 | |
|                 formattingChar = True
 | |
|             
 | |
|             elif fCharacter == "{" and not self.nextCharacterIsNotSpecial:
 | |
|                 self.currentDisplaySpeed += 1
 | |
|                 formattingChar = True
 | |
|             
 | |
|             elif fCharacter == "}" and not self.nextCharacterIsNotSpecial:
 | |
|                 self.currentDisplaySpeed -= 1
 | |
|                 formattingChar = True
 | |
|             
 | |
|             elif fCharacter == "|" and not self.nextCharacterIsNotSpecial: #orange.
 | |
|                 if self.inlineColorStack:
 | |
|                     if self.inlineColorStack[-1] == INLINE_ORANGE:
 | |
|                         del self.inlineColorStack[-1]
 | |
|                     else:
 | |
|                         self.inlineColorStack.append(INLINE_ORANGE)
 | |
|                 else:
 | |
|                     self.inlineColorStack.append(INLINE_ORANGE)
 | |
|                 formattingChar = True
 | |
|             
 | |
|             elif fCharacter == "(" and not self.nextCharacterIsNotSpecial: #blue.
 | |
|                 self.inlineColorStack.append(INLINE_BLUE)
 | |
|                 html = "<font color=\"" + getTextColor(4).name() + "\">" + fCharacter + "</font>"
 | |
|                 self.ao2text.insertHtml(html)
 | |
|                 self.text.insertHtml(html)
 | |
|                 
 | |
|                 self.inlineBlueDepth += 1
 | |
|                 if not self.entireMessageIsBlue and self.animState != 4:
 | |
|                     fChar = self.mChatMessage[CHARNAME]
 | |
|                     f_emote = self.mChatMessage[ANIM]
 | |
|                     if not self.animIsEmpty:
 | |
|                         self.char.playIdle(fChar, f_emote, self.scaling[0])
 | |
|             
 | |
|             elif fCharacter == ")" and not self.nextCharacterIsNotSpecial and self.inlineColorStack:
 | |
|                 if self.inlineColorStack[-1] == INLINE_BLUE:
 | |
|                     del self.inlineColorStack[-1]
 | |
|                     html = "<font color=\"" + getTextColor(4).name() + "\">" + fCharacter + "</font>"
 | |
|                     self.ao2text.insertHtml(html)
 | |
|                     self.text.insertHtml(html)
 | |
|                     
 | |
|                     if self.inlineBlueDepth > 0:
 | |
|                         self.inlineBlueDepth -= 1
 | |
|                         
 | |
|                         if not self.entireMessageIsBlue:
 | |
|                             if self.inlineBlueDepth == 0 and self.animState != 4 and not (self.tickPos+1 >= len(fMessage)):
 | |
|                                 fChar = self.mChatMessage[CHARNAME]
 | |
|                                 f_emote = self.mChatMessage[ANIM]
 | |
|                                 self.char.playTalking(fChar, f_emote, self.scaling[0])
 | |
|                 else:
 | |
|                     self.nextCharacterIsNotSpecial = True
 | |
|                     self.tickPos -= 1
 | |
|             
 | |
|             elif fCharacter == "[" and not self.nextCharacterIsNotSpecial: #gray.
 | |
|                 self.inlineColorStack.append(INLINE_GRAY)
 | |
|                 html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
 | |
|                 self.ao2text.insertHtml(html)
 | |
|                 self.text.insertHtml(html)
 | |
|                 
 | |
|             elif fCharacter == "]" and not self.nextCharacterIsNotSpecial and self.inlineColorStack:
 | |
|                 if self.inlineColorStack[-1] == INLINE_GRAY:
 | |
|                     del self.inlineColorStack[-1]
 | |
|                     html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
 | |
|                     self.ao2text.insertHtml(html)
 | |
|                     self.text.insertHtml(html)
 | |
|                 else:
 | |
|                     self.nextCharacterIsNotSpecial = True
 | |
|                     self.tickPos -= 1
 | |
|             
 | |
|             elif fCharacter == "`" and not self.nextCharacterIsNotSpecial: #green.
 | |
|                 if self.inlineColorStack:
 | |
|                     if self.inlineColorStack[-1] == INLINE_GREEN:
 | |
|                         del self.inlineColorStack[-1]
 | |
|                     else:
 | |
|                         self.inlineColorStack.append(INLINE_GREEN)
 | |
|                 else:
 | |
|                     self.inlineColorStack.append(INLINE_GREEN)
 | |
|                 formattingChar = True
 | |
| 
 | |
|             elif fCharacter == "~" and not self.nextCharacterIsNotSpecial: #green.
 | |
|                 if self.inlineColorStack:
 | |
|                     if self.inlineColorStack[-1] == INLINE_RED:
 | |
|                         del self.inlineColorStack[-1]
 | |
|                     else:
 | |
|                         self.inlineColorStack.append(INLINE_RED)
 | |
|                 else:
 | |
|                     self.inlineColorStack.append(INLINE_RED)
 | |
|                 formattingChar = True
 | |
| 
 | |
|             elif fCharacter == "s" and self.nextCharacterIsNotSpecial: # shake
 | |
|                 self.setScreenShake(True)
 | |
|                 self.nextCharacterIsNotSpecial = False
 | |
| 
 | |
|             elif fCharacter == "f" and self.nextCharacterIsNotSpecial: # flash
 | |
|                 self.setWhiteFlash(True, 0, 75)
 | |
|                 self.nextCharacterIsNotSpecial = False
 | |
| 
 | |
|             elif fCharacter == "n" and self.nextCharacterIsNotSpecial: # newline
 | |
|                 self.text.insertPlainText("\n")
 | |
|                 self.ao2text.insertPlainText("\n")
 | |
|                 self.nextCharacterIsNotSpecial = False
 | |
|             
 | |
|             else:
 | |
|                 self.nextCharacterIsNotSpecial = False
 | |
|                 if self.inlineColorStack:
 | |
|                     top_color = self.inlineColorStack[-1]
 | |
|                     if top_color == INLINE_ORANGE:
 | |
|                         html = "<font color=\"" + getTextColor(C_ORANGE).name() + "\">" + fCharacter + "</font>"
 | |
|                         self.ao2text.insertHtml(html)
 | |
|                         self.text.insertHtml(html)
 | |
|                     elif top_color == INLINE_BLUE:
 | |
|                         html = "<font color=\"" + getTextColor(C_BLUE).name() + "\">" + fCharacter + "</font>"
 | |
|                         self.ao2text.insertHtml(html)
 | |
|                         self.text.insertHtml(html)
 | |
|                     elif top_color == INLINE_GREEN:
 | |
|                         html = "<font color=\"" + getTextColor(C_GREEN).name() + "\">" + fCharacter + "</font>"
 | |
|                         self.ao2text.insertHtml(html)
 | |
|                         self.text.insertHtml(html)
 | |
|                     elif top_color == INLINE_GRAY:
 | |
|                         html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
 | |
|                         self.ao2text.insertHtml(html)
 | |
|                         self.text.insertHtml(html)
 | |
|                     elif top_color == INLINE_RED:
 | |
|                         html = "<font color=\"" + getTextColor(C_RED).name() + "\">" + fCharacter + "</font>"
 | |
|                         self.ao2text.insertHtml(html)
 | |
|                         self.text.insertHtml(html)
 | |
|                     else:
 | |
|                         self.text.insertHtml(fCharacter)
 | |
|                         self.ao2text.insertHtml(fCharacter)
 | |
|                 else:
 | |
|                     if int(self.mChatMessage[TEXT_COLOR]) == C_RAINBOW:
 | |
|                         self.text.insertHtml(fCharacter)
 | |
|                     else:
 | |
|                         self.ao2text.insertHtml(fCharacter)
 | |
|                 
 | |
|                 if self.messageIsCentered:
 | |
|                     self.ao2text.setAlignment(QtCore.Qt.AlignCenter)
 | |
|                     self.text.setAlignment(QtCore.Qt.AlignCenter)
 | |
|                 else:
 | |
|                     self.ao2text.setAlignment(QtCore.Qt.AlignLeft)
 | |
|                     self.text.setAlignment(QtCore.Qt.AlignLeft)
 | |
|             
 | |
|                 if fMessage[self.tickPos] != " " or self.blankBlip:
 | |
|                     if self.blipPos % self.blipRate == 0 and not formattingChar:
 | |
|                         self.blipPos = 0
 | |
|                         if self.blipSound:
 | |
|                             audio.playHandle(self.blipSound, True)
 | |
|                     
 | |
|                     self.blipPos += 1
 | |
|             
 | |
|             self.tickPos += 1
 | |
|             
 | |
|             if self.currentDisplaySpeed < 0:
 | |
|                 self.currentDisplaySpeed = 0
 | |
|             elif self.currentDisplaySpeed > 6:
 | |
|                 self.currentDisplaySpeed = 6
 | |
| 
 | |
|             if formattingChar:
 | |
|                 self.chatTickTimer.start(1)
 | |
|             else:
 | |
|                 self.chatTickTimer.start(self.messageDisplaySpeed[self.currentDisplaySpeed])
 | |
|                  
 | |
|     def inboxTimerTimeout(self):
 | |
|         if len(self.inboxQueue) > 0:
 | |
|             del self.inboxQueue[0]
 | |
|             if len(self.inboxQueue) > 0:
 | |
|                 self.handleChatMessage1(self.inboxQueue[0])
 | |
| 
 | |
|     def playRealization(self):
 | |
|         audio.playHandle(self.sndRealization, True)
 | |
| 
 | |
|     def playObjectionSound(self, charName, objection):
 | |
|         # TODO: Play objection sound when charname is unicode
 | |
|         try:
 | |
|             charName = str(charName)
 | |
|         except:
 | |
|             print "[warning] Can't play objection sound if charName is unicode yet"
 | |
|             return
 | |
|     
 | |
|         if self.sndObjection:
 | |
|             if audio.handleIsActive(self.sndObjection):
 | |
|                 audio.stopHandle(self.sndObjection)
 | |
|             audio.freeHandle(self.sndObjection)
 | |
| 
 | |
|         objecting = ["holdit", "objection", "takethat", "custom"][objection - 1]
 | |
|         
 | |
|         if objecting:
 | |
|             if exists(AOpath + 'characters/' + charName + '/' + objecting + '.wav'):
 | |
|                 self.sndObjection = audio.loadHandle(False, AOpath + 'characters/' + charName + '/' + objecting + '.wav', 0, 0, 0)
 | |
|             elif exists(AOpath + 'characters/' + charName + '/' + objecting + '.opus'):
 | |
|                 self.sndObjection = audio.loadHandle(False, AOpath + 'characters/' + charName + '/' + objecting + '.opus', 0, 0, 0)
 | |
|             else:
 | |
|                 self.sndObjection = None
 | |
|                 if ini.read_ini_bool("AO2XP.ini", "General", "download sounds", True):
 | |
|                     thread.start_new_thread(downloadThread, ("base/characters/"+charName+"/"+objecting+".wav", AOpath + "characters/"+charName+"/"+objecting.lower() + ".wav"))
 | |
|                     thread.start_new_thread(downloadThread, ("base/characters/"+charName+"/"+objecting+".opus", AOpath + "characters/"+charName+"/"+objecting.lower() + ".wav"))
 | |
| 
 | |
|                 if exists(AOpath + 'sounds/general/sfx-objection.opus'):
 | |
|                     self.sndObjection = audio.loadHandle(False, AOpath + 'sounds/general/sfx-objection.opus', 0, 0, 0)
 | |
|                 else:
 | |
|                     self.sndObjection = audio.loadHandle(False, AOpath + 'sounds/general/sfx-objection.wav', 0, 0, 0)
 | |
|             audio.setHandleAttr(self.sndObjection, BASS_ATTRIB_VOL, self.sliSoundVolume.value() / 100.0)
 | |
|             audio.playHandle(self.sndObjection, True)
 | |
|             
 | |
|     def populateSoundList(self):
 | |
|         self.boxSounds.clear()
 | |
|         self.boxSounds.addItem("Default")
 | |
|         if exists("base/soundlist.ini"):
 | |
|             with open("base/soundlist.ini") as f:
 | |
|                 for sound in f.read().split("\n"):
 | |
|                     if not sound: continue
 | |
|                     self.boxSounds.addItem(sound.strip())
 | |
| 
 | |
|     
 | |
|     def playSfx(self):
 | |
|         sfxName = self.mChatMessage[SFX]
 | |
|         if sfxName == "1" or sfxName == "0":
 | |
|             return
 | |
|         
 | |
|         self.playSound(sfxName)
 | |
| 
 | |
|     def playSound(self, sfx):
 | |
|         self.soundChannel = (self.soundChannel + 1) % self.soundChannels
 | |
|         
 | |
|         if self.sound[self.soundChannel]:
 | |
|             if audio.handleIsActive(self.sound[self.soundChannel]):
 | |
|                 audio.stopHandle(self.sound[self.soundChannel])
 | |
|             audio.freeHandle(self.sound[self.soundChannel])
 | |
|             
 | |
|         path = testPath(
 | |
|             AOpath + 'sounds/general/' + sfx,
 | |
|             AOpath + 'sounds/general/' + sfx + '.wav',
 | |
|             AOpath + 'sounds/general/' + sfx + '.opus'
 | |
|         )
 | |
|         
 | |
|         if path:
 | |
|             self.sound[self.soundChannel] = audio.loadHandle(False, path, 0, 0, 0)
 | |
|             audio.setHandleAttr(self.sound[self.soundChannel], BASS_ATTRIB_VOL, self.sliSoundVolume.value() / 100.0)
 | |
|             if self.sound[self.soundChannel]:
 | |
|                 audio.playHandle(self.sound[self.soundChannel], True)
 | |
|             
 | |
|     def playMusic(self, mus):
 | |
|         self.stopMusic()
 | |
|         if mus == "~stop.mp3" or not mus:
 | |
|             self.setCurrentMusicURL(None)
 | |
|             return
 | |
|             
 | |
|         _musicList = self.musicListPrivate if self.privateMusicSelected else self.musicList
 | |
|         
 | |
|         if not mus.endswith(".mp3") and "===MUSIC START===.mp3" in _musicList: #vidya workaround
 | |
|             mus += ".mp3"
 | |
|         musl = mus.lower()
 | |
|         
 | |
|         playLocal = False
 | |
|         
 | |
|         if exists(AOpath + 'sounds/music/' + musl):
 | |
|             playLocal = True
 | |
|         elif self.pickedMusicItem:
 | |
|             _musl = _musicList[self.musicItems.currentItem().text()]
 | |
|             if exists(AOpath + 'sounds/music/' + _musl):
 | |
|                 musl = _musl
 | |
|                 playLocal = True
 | |
|         elif musl.startswith("http"):
 | |
|             _musl = urllib.unquote(basename(mus))
 | |
|             if exists(AOpath + 'sounds/music/' + _musl):
 | |
|                 musl = _musl
 | |
|                 playLocal = True
 | |
|                 
 | |
|         self.pickedMusicItem = False
 | |
|         
 | |
|         if playLocal:
 | |
|             if isinstance(musl, unicode):
 | |
|                 if platform.system() == "Windows":
 | |
|                     musl = musl.encode('mbcs')
 | |
|                 else:
 | |
|                     musl = musl.encode('utf-8')
 | |
|             self.music = audio.loadHandle(False, AOpath + 'sounds/music/' + musl, 0, 0, BASS_SAMPLE_LOOP)
 | |
|             if self.music:
 | |
|                 audio.setHandleAttr(self.music, BASS_ATTRIB_VOL, self.sliMusicVolume.value() / 100.0)
 | |
|                 audio.playHandle(self.music, True)
 | |
|                 self.setCurrentMusicURL(mus)
 | |
|                 if self.sliMusicVolume.value() == 0:
 | |
|                     audio.pauseHandle(self.music)
 | |
|             else:
 | |
|                 error = audio.getBassError()
 | |
|                 print "[audio] Couldn't play local track! Error", error
 | |
|             
 | |
|         elif ini.read_ini_bool("AO2XP.ini", "General", "download music", True):
 | |
|             if musl.startswith("http"):
 | |
|                 self.music = audio.loadURLHandle(mus, 0, BASS_SAMPLE_LOOP)
 | |
|                 print "[audio] Trying to play", mus
 | |
|             else:
 | |
|                 global bucket
 | |
|                 mus = musl = bucket + 'base/sounds/music/' + musl.replace(" ", "%20")
 | |
|                 print "[audio] Music stream:", bucket + 'base/sounds/music/' + mus
 | |
|                 self.music = audio.loadURLHandle(musl, 0, BASS_SAMPLE_LOOP)
 | |
| 
 | |
|             if self.music:
 | |
|                 audio.setHandleAttr(self.music, BASS_ATTRIB_VOL, self.sliMusicVolume.value() / 100.0)
 | |
|                 audio.playHandle(self.music, True)
 | |
|                 self.setCurrentMusicURL(mus)
 | |
|                 if self.sliMusicVolume.value() == 0:
 | |
|                     audio.pauseHandle(self.music)
 | |
|             else:
 | |
|                 # Evil HTTPS hack for XP systems
 | |
|                 error = audio.getBassError()
 | |
|                 musext = os.path.splitext(basename(musl))[-1]
 | |
|                 if musext in ['.xm', '.mod', '.mo3', '.it', '.s3m', '.mtm', '.umx']:
 | |
|                     # BASS can play modules, so might as well support them
 | |
|                     self.specialStream = True
 | |
|                 if (musl.startswith("https") and error == 2) or self.specialStream:
 | |
|                     print "[audio] Downloading music with urllib2"
 | |
|                     self.downloadThread = MusicDownloadThread(self, mus.replace(" ", "%20"))
 | |
|                     self.downloadThread.finished_signal.connect(self.playDownloadedMusic)
 | |
|                     self.downloadThread.start()
 | |
|                 else:
 | |
|                     print "[audio] Couldn't play music. Error", error
 | |
| 
 | |
|     def stopMusic(self):
 | |
|         if self.music:
 | |
|             if audio.handleIsActive(self.music):
 | |
|                 audio.stopHandle(self.music)
 | |
|             if self.specialStream:
 | |
|                 audio.freeMOD(self.music)
 | |
|                 self.specialStream = False
 | |
|             else:
 | |
|                 audio.freeHandle(self.music)
 | |
|             if self.stream:
 | |
|                 self.stream = None
 | |
|                 
 | |
|         if self.downloadThread:
 | |
|             self.downloadThread.stop()
 | |
|             self.downloadThread = None
 | |
|             
 | |
|     def playDownloadedMusic(self, file_length, url):
 | |
|         # Part of the evil HTTPS music download hack for XP systems
 | |
|         if self.specialStream:
 | |
|             self.music = audio.loadMOD(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP)
 | |
|         else:
 | |
|             self.music = audio.loadHandle(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP)
 | |
|         if self.music:
 | |
|             print "[audio] Done downloading; playing stream"
 | |
|             audio.setHandleAttr(self.music, BASS_ATTRIB_VOL, self.sliMusicVolume.value() / 100.0)
 | |
|             audio.playHandle(self.music, True)
 | |
|             self.setCurrentMusicURL(url)
 | |
|             if self.sliMusicVolume.value() == 0:
 | |
|                 audio.pauseHandle(self.music)
 | |
|         else:
 | |
|             print "[audio] Done downloading, but the stream couldn't be played. Error", audio.getBassError()
 | |
|     
 | |
|     def setCurrentMusicURL(self, url):
 | |
|         self.currentMusicURL = url
 | |
|         self.actMusicAddCurrent.setDisabled(url is None)
 | |
| 
 | |
|     def loadAllMusic(self):
 | |
|         _musicList = self.musicListPrivate if self.privateMusicSelected else self.musicList
 | |
|         
 | |
|         self.actMusicRandom.setDisabled(not len(_musicList.items()))
 | |
|     
 | |
|         for song, fname in _musicList.items():
 | |
|             songitem = QtGui.QListWidgetItem()
 | |
|             songitem.setText(song)
 | |
|             if not self.privateMusicSelected and exists(unicode(AOpath + 'sounds/music/' + decodeAOString(fname).lower())):
 | |
|                 songitem.setBackgroundColor(QtGui.QColor(self.foundSongItemColor))
 | |
|             self.musicItems.addItem(songitem)
 | |
| 
 | |
|     def loadAllEvidence(self, evi):
 | |
|         self.evidence = evi
 | |
| 
 | |
|         if self.boxEvidence.count() > 0:
 | |
|             self.boxEvidence.clear()
 | |
|         for evi in self.evidence:
 | |
|             while len(evi) < 3: # new AO 2.9 bug where they never correctly escaped evidence name/desc/image on FantaProtocol
 | |
|                 evi += [""]
 | |
|             evi[0] = decodeAOString(evi[0].decode('utf-8'))
 | |
|             evi[1] = decodeAOString(evi[1].decode('utf-8'))
 | |
|             evi[2] = decodeAOString(evi[2].decode('utf-8'))
 | |
|             self.boxEvidence.addItem(evi[0].strip())
 | |
| 
 | |
|         if not self.evidence:
 | |
|             self.boxEvidence.setCurrentIndex(0)
 | |
|             self.evidenceDescription.setText('.')
 | |
|         else:
 | |
|             self.boxEvidence.setCurrentIndex(self.selectedEvidence)
 | |
|             
 | |
|     def updatePlayerList(self, pid, op, utype, data=""):
 | |
|         if not self.playerList:
 | |
|             return
 | |
|             
 | |
|         pid = str(pid)
 | |
|         if op == 0: # Add or remove player
 | |
|             if utype == 0: # Add a player
 | |
|                 self.playerItems.addItem("[%s]" % pid)
 | |
|                 if not pid in self.playerList:
 | |
|                     self.playerList[pid] = ["", "", "", ""]
 | |
|             if utype == 1: # Remove a player
 | |
|                 item = self.playerItems.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
 | |
|                 if item:
 | |
|                     self.playerItems.takeItem(self.playerItems.row(item[0]))
 | |
|                 if pid in self.playerList:
 | |
|                     del self.playerList[pid]
 | |
|         else: # Update a player
 | |
|             if pid in self.playerList:
 | |
|                 self.playerList[pid][utype] = data
 | |
|                 
 | |
|             item = self.playerItems.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
 | |
|             if item:
 | |
|                 name = self.playerList[pid][0]
 | |
|                 char = self.playerList[pid][1]
 | |
|                 charName = self.playerList[pid][2]
 | |
|                 text = "[%s]" % pid
 | |
|                 if char:
 | |
|                     text += " %s" % char
 | |
|                 if charName:
 | |
|                     text += " (%s)" % charName
 | |
|                 if name:
 | |
|                     text += " %s" % name
 | |
|                 item[0].setText(text)
 | |
|     
 | |
|     def startPauseOnscreenTimers(self, command, timer_id, timer_ms):
 | |
|         if timer_id > 4:
 | |
|             return
 | |
|         
 | |
|         if command == 0:
 | |
|             if not self.onscreenTimer.isActive():
 | |
|                 self.onscreenTimer.start(self.onscreenTimerTick)
 | |
|             self.onscreenTimerTimes[timer_id] = timer_ms
 | |
|             self.onscreenTimerPaused[timer_id] = False
 | |
|             self.updateOnscreenTimers()
 | |
|             print "[client] Timer %d was started for %d ms" % (timer_id, timer_ms)
 | |
|         elif command == 1:
 | |
|             self.onscreenTimerPaused[timer_id] = True
 | |
|         elif command == 2:
 | |
|             self.onscreenTimerLabels[timer_id].show()
 | |
|         elif command == 3:
 | |
|             self.onscreenTimerLabels[timer_id].hide()
 | |
|     
 | |
|     def updateOnscreenTimers(self):
 | |
|         for timer_id, label in enumerate(self.onscreenTimerLabels):
 | |
|             time_ms = self.onscreenTimerTimes[timer_id]
 | |
|             if not time_ms or self.onscreenTimerPaused[timer_id]:
 | |
|                 continue
 | |
|             
 | |
|             secs = time_ms / 1000
 | |
|             mins = secs / 60
 | |
|             hours = mins / 60
 | |
|             label.setText("%02d:%02d:%02d" % (hours, mins % 60, secs % 60))
 | |
|             
 | |
|             self.onscreenTimerTimes[timer_id] -= self.onscreenTimerTick
 | |
|             if self.onscreenTimerTimes[timer_id] <= 0:
 | |
|                 label.hide()
 | |
|                 self.onscreenTimerTimes[timer_id] = 0
 | |
|                 self.onscreenTimerPaused[timer_id] = True
 | |
|         
 | |
|         if self.onscreenTimerTimes == [0, 0, 0, 0, 0]:
 | |
|             self.onscreenTimer.stop()
 | |
| 
 | |
|     def onDemoClicked(self, item):
 | |
|         fname = demo.getDemoFilename(self.demoItems, item)
 | |
|         
 | |
|         if not fname:
 | |
|             return
 | |
|         
 | |
|         self.playerItems.clear()
 | |
|         self.stopMusic()
 | |
|         self.ICLog.clear()
 | |
|         self.OOCLog.clear()
 | |
|         
 | |
|         if not self.demoPlaying:
 | |
|             self.enableWidgets(True)
 | |
|             self.tcpThread.stop()
 | |
|             self.demoPlaying = True
 | |
|             
 | |
|             self.demoPlayer = demo.DemoPlayer(self)
 | |
|             self.demoPlayer.MS_Chat.connect(self.netmsgMS)
 | |
|             self.demoPlayer.newChar.connect(self.onPVPacket)
 | |
|             self.demoPlayer.newBackground.connect(self.setBackground)
 | |
|             self.demoPlayer.OOC_Log.connect(self.OOCLog.append)
 | |
|             self.demoPlayer.IC_Log.connect(self.ICLog.append)
 | |
|             self.demoPlayer.charSlots.connect(partial(self.charSelect.setCharList, self.charList))
 | |
|             self.demoPlayer.loadAllEvidence.connect(self.loadAllEvidence)
 | |
|             self.demoPlayer.updatePlayerList.connect(self.updatePlayerList)
 | |
|             self.demoPlayer.rainbowColor.connect(self.text.setStyleSheet)
 | |
|             self.demoPlayer.timerUpdate.connect(self.startPauseOnscreenTimers)
 | |
|         
 | |
|         self.demoPlayer.start(fname)
 | |
| 
 | |
|     def demoSeek(self, time):
 | |
|         self.demoPlayer.seek(time)
 | |
| 
 | |
|     def startGame(self, tcp, playerList, charList, musicList, background, evidence, areas, features=[], joinOOC=[], hpList=[], webAO_bucket=""):
 | |
|         self.willDisconnect = False
 | |
|         self.myChar = -1
 | |
|         self.myChatColor = 0
 | |
|         self.tcp = tcp
 | |
|         self.playerList = playerList
 | |
|         self.charList = charList
 | |
|         self.evidence = evidence
 | |
|         self.areas = areas
 | |
|         self.areasLen = len(areas[0])
 | |
|         self.features = features
 | |
|         self.musicList = OrderedDict([])
 | |
|         
 | |
|         # We want only song names without paths or extensions in the music list
 | |
|         for song in musicList:
 | |
|             _basename = os.path.splitext(basename(song))
 | |
|             self.musicList[QtCore.QString(decodeAOString(_basename[0].decode('utf-8')))] = song.decode('utf-8')
 | |
| 
 | |
|         if "base/" in webAO_bucket:
 | |
|             webAO_bucket = webAO_bucket.replace("base/", "")
 | |
|         global bucket
 | |
|         bucket = webAO_bucket
 | |
|         
 | |
|         self.charSelect.setCharList(charList)
 | |
|         autopick = getOption("General", "auto pick").decode('utf-8').lower()
 | |
|         coincidence = -1
 | |
|         for i, char in enumerate(self.charList):
 | |
|             if char[0].lower() == autopick and char[1] == 0:
 | |
|                 coincidence = i
 | |
|                 break
 | |
| 
 | |
|         if coincidence > -1:
 | |
|             self.charSelect.selectChar(coincidence)
 | |
|         else:
 | |
|             self.charSelect.showCharSelect(False)
 | |
| 
 | |
|         # Putting it down here because some servers won't allow you to switch areas without picking a character first
 | |
|         autojoinarea = getOption("General", "auto join area").decode('utf-8')
 | |
|         if autojoinarea != "": self.sendMC(autojoinarea)
 | |
|         
 | |
|         self.OOCNameInput.setText(ini.read_ini("AO2XP.ini", "General", "OOC name", "unnamed"))
 | |
|         self.shownameEdit.setText(ini.read_ini("AO2XP.ini", "General", "Showname"))
 | |
|         
 | |
|         self.enableWidgets()
 | |
|         
 | |
|         self.boxPair.clear()
 | |
|         self.cbPair.setChecked(False)
 | |
|         if "cccc_ic_support" in features:
 | |
|             self.shownameEdit.show()
 | |
|             self.cbNoInterrupt.show()
 | |
|             self.cbPair.setDisabled(False)
 | |
|             self.cbPair.setText("Enable pairing")
 | |
|             for char in charList:
 | |
|                 self.boxPair.addItem(char[0])
 | |
|         else:
 | |
|             self.shownameEdit.hide()
 | |
|             self.cbNoInterrupt.hide()
 | |
|             self.cbPair.setDisabled(True)
 | |
|             self.cbPair.setToolTip("This server does not support pairing.")
 | |
| 
 | |
|         self.cbBench.setDisabled("deskmod" not in features)
 | |
|         self.cbFlip.setDisabled("flipping" not in features)
 | |
|         self.cbSlide.setDisabled(not self.slideEnabled or "custom_blips" not in features)
 | |
|         self.btnCustomObjection.setVisible("customobjections" in features)
 | |
|         self.sliPairOffsetY.setVisible("y_offset" in features)
 | |
|         self.lblPairOffsetY.setVisible("y_offset" in features)
 | |
|         
 | |
|         self.boxColors.clear()
 | |
|         self.boxColors.addItems(['White', 'Green', 'Red', 'Orange', 'Blue'])
 | |
|         if "yellowtext" in features:
 | |
|             self.boxColors.addItems(['Yellow', 'Pink', 'Cyan', 'Gray', 'Rainbow', 'Black'])
 | |
|         self.boxColors.setCurrentIndex(self.myChatColor)
 | |
|         
 | |
|         for hp in hpList:
 | |
|             self.healthbars.emit(hp[0], hp[1])
 | |
| 
 | |
|         for char in self.charList:
 | |
|             if not exists(AOpath + 'characters/' + char[0].lower() + '/char.ini'):
 | |
|                 continue
 | |
|             char[2] = getCharIni(char[0], "Options", "gender").lower()
 | |
|             if not char[2]:
 | |
|                 char[2] = getCharIni(char[0], "Options", "blips").lower()
 | |
|                 if not char[2]:
 | |
|                     char[2] = "male"
 | |
| 
 | |
|         self.btnRealization.setPressed(False)
 | |
|         self.btnCustomObjection.setPressed(False)
 | |
|         self.mutedList.clear()
 | |
|         self.unmutedList.clear()
 | |
|         for char in self.charList:
 | |
|             self.unmutedList.addItem(char[0])
 | |
| 
 | |
|         self.musicItems.clear()
 | |
|         self.areaItems.clear()
 | |
|         self.boxEvidence.clear()
 | |
|         for evi in evidence:
 | |
|             self.boxEvidence.addItem(evi[0].strip())
 | |
| 
 | |
|         logstart = '<b>--- Log started on ' + time.ctime() + ' ---</b>'
 | |
|         if self.OOCLog.toPlainText():
 | |
|             self.OOCLog.append("\n"+logstart)
 | |
|         else:
 | |
|             self.OOCLog.append(logstart)
 | |
|         if self.ICLog.toPlainText():
 | |
|             self.ICLog.append("\n"+logstart)
 | |
|         else:
 | |
|             self.ICLog.append(logstart)
 | |
|         
 | |
|         self.setBackground(background.lower())
 | |
|         self.setScene(True)
 | |
|         self.chatbox.hide()
 | |
|         
 | |
|         for msg in joinOOC:
 | |
|             self.OOCLog.append(msg)
 | |
|         
 | |
|         if self.areasLen:
 | |
|             for i in range(self.areasLen):
 | |
|                 areaitem = QtGui.QListWidgetItem()
 | |
|                 self.areaItems.addItem(areaitem)
 | |
|             self.loadAllMusic()
 | |
|             self.updateAreaList()
 | |
|         else:
 | |
|             self.noARUP = True
 | |
|         
 | |
|         for pid in playerList:
 | |
|             self.updatePlayerList(pid, 0, 0)
 | |
|             for type in range(len(playerList[pid])):
 | |
|                 self.updatePlayerList(pid, 1, type, playerList[pid][type])
 | |
| 
 | |
|         self.sliMusicVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100))
 | |
|         self.sliSoundVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100))
 | |
|         self.sliBlipsVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Blip volume", 100))
 | |
|         
 | |
|         self.onImportEvidence(True)
 | |
| 
 | |
|         self.tcpThread = TCPThread(self)
 | |
|         self.tcpThread.MS_Chat.connect(self.netmsgMS)
 | |
|         self.tcpThread.newChar.connect(self.onPVPacket)
 | |
|         self.tcpThread.newBackground.connect(self.setBackground)
 | |
|         self.tcpThread.OOC_Log.connect(self.OOCLog.append)
 | |
|         self.tcpThread.IC_Log.connect(self.ICLog.append)
 | |
|         self.tcpThread.charSlots.connect(partial(self.charSelect.setCharList, self.charList))
 | |
|         self.tcpThread.showCharSelect.connect(self.charSelect.showCharSelect)
 | |
|         self.tcpThread.loadAllEvidence.connect(self.loadAllEvidence)
 | |
|         self.tcpThread.updatePlayerList.connect(self.updatePlayerList)
 | |
|         self.tcpThread.rainbowColor.connect(self.text.setStyleSheet)
 | |
|         self.tcpThread.timerUpdate.connect(self.startPauseOnscreenTimers)
 | |
|         self.tcpThread.start()
 | |
|         
 | |
|         self.demoPlaying = False
 | |
|         
 | |
|         self.startDemoRecorder(background)
 | |
|         self.ICChatInput.setFocus()
 | |
|     
 | |
|     def startDemo(self, fname):
 | |
|         self.playerList = []
 | |
|         self.charList = []
 | |
|         self.evidence = []
 | |
|         self.areas = []
 | |
|         self.areasLen = 0
 | |
|         self.features = ['noencryption', 'yellowtext', 'prezoom', 'flipping', 'customobjections', 'fastloading', 'deskmod', 'evidence', 'cccc_ic_support', 'arup', 'casing_alerts', 'modcall_reason', 'looping_sfx', 'additive', 'effects', 'y_offset', 'expanded_desk_mods', 'auth_packet', 'custom_blips']
 | |
|         self.musicList = OrderedDict([])
 | |
|         self.charSelect.hide()
 | |
|         self.onPVPacket()
 | |
|         
 | |
|         self.setBackground("default")
 | |
|         self.setScene(True)
 | |
|         self.chatbox.hide()
 | |
|         
 | |
|         self.sliMusicVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100))
 | |
|         self.sliSoundVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100))
 | |
|         self.sliBlipsVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Blip volume", 100))
 | |
|         
 | |
|         self.onImportEvidence(True)
 | |
|     
 | |
|         self.demoPlayer = demo.DemoPlayer(self)
 | |
|         self.demoPlayer.MS_Chat.connect(self.netmsgMS)
 | |
|         self.demoPlayer.newChar.connect(self.onPVPacket)
 | |
|         self.demoPlayer.newBackground.connect(self.setBackground)
 | |
|         self.demoPlayer.OOC_Log.connect(self.OOCLog.append)
 | |
|         self.demoPlayer.IC_Log.connect(self.ICLog.append)
 | |
|         self.demoPlayer.charSlots.connect(partial(self.charSelect.setCharList, self.charList))
 | |
|         self.demoPlayer.loadAllEvidence.connect(self.loadAllEvidence)
 | |
|         self.demoPlayer.updatePlayerList.connect(self.updatePlayerList)
 | |
|         self.demoPlayer.rainbowColor.connect(self.text.setStyleSheet)
 | |
|         self.demoPlayer.timerUpdate.connect(self.startPauseOnscreenTimers)
 | |
|     
 | |
|         self.playerItems.clear()
 | |
|         self.stopMusic()
 | |
|         self.ICLog.clear()
 | |
|         self.OOCLog.clear()
 | |
|         
 | |
|         self.btnChangeChar.setText('Disconnect')
 | |
|         self.enableWidgets(True)
 | |
|         self.demoPlaying = True
 | |
|         self.demoPlayer.start(fname)
 | |
|     
 | |
|     def startDemoRecorder(self, bg=None):
 | |
|         if ini.read_ini_bool("AO2XP.ini", "General", "record demos", False):
 | |
|             self.demoRecorder = demo.DemoRecorder()
 | |
|             self.demoRecorder.start()
 | |
|             self.demoRecorder.record([["SC"] + [char[0] for char in self.charList]], encode=True)
 | |
|             if bg:
 | |
|                 self.demoRecorder.record([["BN", bg, ""]], encode=True)
 | |
|   
 | |
|     def enableWidgets(self, demo = False):
 | |
|         for widget in [
 | |
|             self.OOCInput, self.btnCallMod,
 | |
|             self.OOCNameInput, self.OOCLogin, self.tabEvidence,
 | |
|             self.tabQueue, self.tabIniSwap, self.tabMute,
 | |
|             self.tabPair, self.tabMisc, self.tabPlayers,
 | |
|             self.tabMusic, self.boxEmotes, self.boxPositions,
 | |
|             self.cbFlip, self.cbPreanim, self.cbNoInterrupt,
 | |
|             self.boxEffects, self.cbSlide, self.cbBench,
 | |
|             self.cbAdditive, self.areaItems,
 | |
|             self.boxColors, self.btnDefenseBar.btnMinus, self.btnProsecutionBar.btnMinus,
 | |
|             self.btnDefenseBar.btnPlus, self.btnProsecutionBar.btnPlus, self.btnWitnessTestimony,
 | |
|             self.btnCrossExamination, self.btnNotGuilty, self.btnGuilty,
 | |
|             self.btnRealization, self.btnShake,
 | |
|             ]:
 | |
|             widget.setEnabled(not demo)
 | |
|         self.sliDemoSeekbar.setVisible(demo)
 | |
|         self.shownameEdit.setVisible(not demo)
 | |
|         self.ICChatInput.setVisible(not demo)
 | |
|         
 | |
|         if demo:
 | |
|             self.btnChangeChar.setText('Disconnect')
 | |
|         else:
 | |
|             self.btnChangeChar.setText('Switch &character')
 | |
|             
 | |
|     def updateAreaList(self):
 | |
|         try:
 | |
|             for i in range(self.areasLen):
 | |
|                 areaPlayers = self.areas[0][i]
 | |
|                 areaStatus = self.areas[1][i].title()
 | |
|                 areaCM = self.areas[2][i].decode('utf-8')
 | |
|                 areaLocked = self.areas[3][i].title()
 | |
|                 areaName = self.areas[4][i].decode('utf-8')
 | |
|                 if areaStatus == "Casing":
 | |
|                     self.areaItems.item(i).setText("%s\n%s | %s\n%s users | %s" % (areaName, areaStatus, areaCM, areaPlayers, areaLocked))
 | |
|                 else:
 | |
|                     self.areaItems.item(i).setText("%s\n%s\n%s users | %s" % (areaName, areaStatus, areaPlayers, areaLocked))
 | |
|                     
 | |
|                 if areaLocked == "Locked":
 | |
|                     self.areaItems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "lock.png"))
 | |
|                 else:
 | |
|                     self.areaItems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "house.png"))
 | |
|         except Exception as e:
 | |
|             print "[debug] Couldn't update areas. Details:"
 | |
|             print "[debug]", e |