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) 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] There's no response, 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) else: print "[audio] There's no response, 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("", "").replace("", "") +"\n") else: logfile.write("[OOC] " + text_.replace("", "").replace("", "") +"\n") else: logfile.write(text_.replace("", "").replace("", "") + "\n") else: text_ = text.toUtf8() if self.combinelog: if self.type == 0: logfile.write("[IC] " + text_.replace("", "").replace("", "") +"\n") else: logfile.write("[OOC] " + text_.replace("", "").replace("", "") +"\n") else: logfile.write(text_.replace("", "").replace("", "") +"\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): QtGui.QLabel.__init__(self, parent) self.parent = parent 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, taller): if taller: return QtCore.Qt.KeepAspectRatio else: return QtCore.Qt.KeepAspectRatioByExpanding 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().width() <= self.size().width()) 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.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.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) def resetGeometry(self): self.geometrySet = False class GUI(QtGui.QWidget): gamewindow = None sound = 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 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.viewport = QtGui.QWidget(self) 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.char.done.connect(self.preanimDone) self.sideChar = AOCharMovie(self.viewport) self.sideChar.hide() self.slideLastWit = [] self.slideLastPos = None self.slideWitness = AOCharMovie(self.viewport) self.slideWitness.showOnPlay = False self.slideWitness.hide() self.slideSpeaker = AOCharMovie(self.viewport) 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.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) label.hide() label.setText("00:00:00") label.setStyleSheet('color: white;') self.onscreenTimerLabels.append(label) self.onscreenTimerLabels[0].setAlignment(QtCore.Qt.AlignCenter) self.onscreenTimerLabels[3].setAlignment(QtCore.Qt.AlignRight) self.onscreenTimerLabels[4].setAlignment(QtCore.Qt.AlignRight) self.onscreenTimerLabels[2].move(self.onscreenTimerLabels[1].x(), self.onscreenTimerLabels[1].y() + self.onscreenTimerLabels[1].size().height() + 4) self.onscreenTimerLabels[4].move(self.onscreenTimerLabels[3].x(), self.onscreenTimerLabels[3].y() + self.onscreenTimerLabels[3].size().height() + 4) # 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.OOCNameInput = QtGui.QLineEdit(self) self.OOCNameInput.setPlaceholderText('Enter a name...') self.OOCInput = QtGui.QLineEdit(self) self.OOCInput.setPlaceholderText('Server chat/OOC chat...') self.OOCInput.returnPressed.connect(self.onOOCReturn) 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) # 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.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.layMisc.addWidget(self.cbMockText) self.layMisc.addWidget(self.cbSpacing) self.layMisc.addWidget(self.cbAutoCaps) # 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.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.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.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.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.btnChangeChar = QtGui.QPushButton(self) self.btnChangeChar.clicked.connect(self.onChangeCharClicked) self.btnCallMod = QtGui.QPushButton(self) self.btnCallMod.setText('Call mod') self.btnCallMod.clicked.connect(self.onCallModClicked) self.btnSettings = QtGui.QPushButton("Settings", self) self.btnSettings.clicked.connect(self.gamewindow.showSettings) self.boxEmotes = QtGui.QComboBox(self) self.boxEmotes.currentIndexChanged.connect(partial(self.changeEmote, True)) self.boxEmotes.setToolTip('Select an emotion for your character') self.boxColors = QtGui.QComboBox(self) self.boxColors.currentIndexChanged.connect(self.setChatColor) self.boxColors.setToolTip('Change the color of your message') 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.boxEffects = QtGui.QComboBox(self) self.boxEffects.currentIndexChanged.connect(self.ICChatFocus) self.boxEffects.setToolTip('Show this effect on your next message') 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.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.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.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.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') # Emotions self.btnPrevEmotePage = buttons.BackEmoteButton(self) self.btnPrevEmotePage.hide() self.btnNextEmotePage = buttons.NextEmoteButton(self) self.btnNextEmotePage.show() 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.sndRealization = audio.loadHandle(False, AOpath + 'sounds/general/sfx-realization.wav', 0, 0, 0) 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.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.btnTakeThat = buttons.Objections(self, 3) self.btnTakeThat.clicked.connect(self.ICChatFocus) self.btnTakeThat.setToolTip("Take that!") self.btnObjection = buttons.Objections(self, 2) self.btnObjection.clicked.connect(self.ICChatFocus) self.btnObjection.setToolTip("Objection!") self.btnHoldIt = buttons.Objections(self, 1) self.btnHoldIt.clicked.connect(self.ICChatFocus) self.btnHoldIt.setToolTip("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.btnProsecutionBar = buttons.PenaltyBars(self, 2) self.btnProsecutionBar.minusClicked.connect(self.onPenaltyBarMinusClicked) self.btnProsecutionBar.plusClicked.connect(self.onPenaltyBarPlusClicked) self.btnWitnessTestimony = buttons.WTCEbuttons(self, 0) self.btnWitnessTestimony.clicked.connect(self.OnWTCEButtonClicked) self.btnCrossExamination = buttons.WTCEbuttons(self, 1) self.btnCrossExamination.clicked.connect(self.OnWTCEButtonClicked) self.btnNotGuilty = buttons.WTCEbuttons(self, 2, 0) self.btnNotGuilty.clicked.connect(self.OnWTCEButtonClicked) self.btnGuilty = buttons.WTCEbuttons(self, 2, 1) self.btnGuilty.clicked.connect(self.OnWTCEButtonClicked) 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) # 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.gamewindow.setObjectName("mainWindow") self.lblMusicVolume.setObjectName("lblMusicVolume") self.lblSoundVolume.setObjectName("lblSoundVolume") self.lblBlipsVolume.setObjectName("lblBlipsVolume") 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") # 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.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.viewportScale = 1 self.nameFontPointSize = 12 self.textFontPointSize = 24 self.emotePageGeometry = (526, 384, 288, 98) self.loadTheme() def loadTheme(self, switching=False): theme = getOption("General", "theme", "default") try: stylesheet = "" self.gamewindow.setStyleSheet("") self.chatbox.resetGeometry() self.btnRealization.setPixmaps(theme) self.btnShake.setPixmaps(theme) self.btnObjection.setPixmaps(theme) self.btnTakeThat.setPixmaps(theme) self.btnHoldIt.setPixmaps(theme) with open(AO2XPpath + "ao2xp_themes/" + theme + "/theme.py") as t: exec t if switching: # This is to reset the colors on the music list. Not necessary on startup self.onMusicSearch("") self.viewportScale = self.viewport.height() / float(192) self.court.resize(self.viewport.size()) self.bench.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.ao2text.setGeometry(self.text.geometry()) self.ao2text.setStyleSheet(self.text.styleSheet()) # Theme chatbox chatboxPixmap = QtGui.QPixmap(testPath( 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.resize(self.chatboxWidth, self.chatboxHeight) self.chatbox.move(0, self.viewport.height() - 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 += "QWidget#mainWindow { 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 = None nameFont = None textFont = None fontDb = QtGui.QFontDatabase() fontDb.addApplicationFont(AO2XPpath + 'font/Igiari.ttf') fontDb.addApplicationFont(AO2XPpath + 'font/Ace_Name_Regular.ttf') nameFont = QtGui.QFont("Ace Name") textFont = QtGui.QFont("Igiari") nameFont.setPointSize(self.nameFontPointSize) textFont.setPointSize(self.textFontPointSize) self.text.setFont(textFont) self.ao2text.setFont(textFont) self.name.setFont(nameFont) for label in self.onscreenTimerLabels: label.resize(self.viewport.width(), label.sizeHint().height()) label.setFont(nameFont) 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 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(random.randint(-shakeForce, shakeForce), self.viewport.height() - self.chatboxHeight + random.randint(-shakeForce, shakeForce)) self.ao2text.move(-self.chatbox.x()+16, (self.viewport.height()-self.chatboxHeight-self.chatbox.y())+32) self.text.move(-self.chatbox.x()+16, (self.viewport.height()-self.chatboxHeight-self.chatbox.y())+-1) 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(0, self.viewport.height()-self.chatboxHeight) self.ao2text.move(16, 32) self.text.move(16,32) 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): if self.sound: 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.minusbtn.show() self.btnDefenseBar.plusbtn.show() self.btnProsecutionBar.minusbtn.show() self.btnProsecutionBar.plusbtn.show() self.btnWitnessTestimony.show() self.btnCrossExamination.show() self.btnNotGuilty.show() self.btnGuilty.show() else: self.btnDefenseBar.minusbtn.hide() self.btnDefenseBar.plusbtn.hide() self.btnProsecutionBar.minusbtn.hide() self.btnProsecutionBar.plusbtn.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 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 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 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] if self.cbNoInterrupt.isChecked(): 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 += emote[2]+"#" #anim msg += text+"#" msg += self.charSide+"#" msg += (ini.get_effect_sound(self.boxEffects.currentText(), self.charName) if self.boxEffects.currentIndex() > 0 else emote[4])+"#" #sfx 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) # 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]) examine = chatMsgComp == ">" or chatMsgComp == "<" or chatMsgComp == "=" special = not chatMsgComp or chatMsgComp.isspace() 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() 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] if mChatMessage[SHOWNAME] and mChatMessage[SHOWNAME].lower() != fChar.lower(): try: logcharName += " (" + mChatMessage[SHOWNAME]+")" except: logcharName += " (???)" if evidence == -1: self.ICLog.append(timestamp + '%s: %s' % (logcharName, chatmsg.replace("<", "<"))) else: eviname = '(NULL) %d' % evidence try: eviname = self.evidence[evidence][0] except: pass self.ICLog.append(timestamp + '%s: %s\n%s presented an evidence: %s' % (logcharName, chatmsg, fChar, eviname.strip())) self.isAdditive = (mChatMessage[ADDITIVE] == "1") 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 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: side = self.mChatMessage[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 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 self.mChatMessage[FLIP] == "1": self.char.setFlipped(True) else: self.char.setFlipped(False) side = self.mChatMessage[SIDE] emoteMod = int(self.mChatMessage[EMOTE_MOD]) no_preanim = not self.mChatMessage[PREANIM] or self.mChatMessage[PREANIM] == "-" # AO 2.8: always offset player hor_offset = vert_offset = 0 if "y_offset" in self.features: # AO 2.9 keyword = "" if "" 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 = "" if "" 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 == 1 or emoteMod == 2 or emoteMod == 6) and self.mChatMessage[PREANIM] != "-": # sfxDelay = int(self.mChatMessage[SFX_DELAY]) * 60 # if sfxDelay > 0: # self.sfxDelayTimer.start(sfxDelay) # else: # self.playSfx() self.setBench(True) self.playPre(False) elif emoteMod == 0 or emoteMod == 5 or no_preanim: if self.mChatMessage[NO_INTERRUPT] == "0" or no_preanim: 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 #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 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 self.mChatMessage[CHATMSG].lower().split(" "): self.OOCLog.append("%s called you: %s" % (fChar, self.mChatMessage[CHATMSG])) QtGui.QApplication.alert(self, 1000) snd = audio.loadHandle(False, "word_call.wav", 0, 0, BASS_STREAM_AUTOFREE) if snd: audio.playHandle(snd, True) break 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() 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 = "" + fCharacter + "" 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 = "" + fCharacter + "" 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 = "" + fCharacter + "" 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 = "" + fCharacter + "" 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 = "" + fCharacter + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_BLUE: html = "" + fCharacter + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_GREEN: html = "" + fCharacter + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_GRAY: html = "" + fCharacter + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_RED: html = "" + fCharacter + "" 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): 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 playSfx(self): sfxName = self.mChatMessage[SFX] if sfxName == "1" or sfxName == "0": return self.playSound(sfxName) def playSound(self, sfx): if self.sound: if audio.handleIsActive(self.sound): audio.stopHandle(self.sound) audio.freeHandle(self.sound) path = testPath(AOpath + 'sounds/general/' + sfx, AOpath + 'sounds/general/' + sfx + '.wav', AOpath + 'sounds/general/' + sfx + '.opus') if path: self.sound = audio.loadHandle(False, path, 0, 0, 0) audio.setHandleAttr(self.sound, BASS_ATTRIB_VOL, self.sliSoundVolume.value() / 100.0) if self.sound: audio.playHandle(self.sound, True) def playMusic(self, mus): self.stopMusic() if mus == "~stop.mp3" or not mus: 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) 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) if self.sliMusicVolume.value() == 0: audio.pauseHandle(self.music) else: error = audio.getBassError() #print "[audio] Couldn't play music. Error", error # Here comes the evil HTTPS hack for XP systems, but it also allows us to download and play modules, because, why not? musext = os.path.splitext(basename(musl))[-1] if musext in ['.xm', '.mod', '.mo3', '.it', '.s3m', '.mtm', '.umx']: 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() 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.wait() self.downloadThread = None def playDownloadedMusic(self, file_length): # Part of the evil HTTPS music download hack for XP systems print "[audio] Done downloading; playing stream" 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) audio.setHandleAttr(self.music, BASS_ATTRIB_VOL, self.sliMusicVolume.value() / 100.0) audio.playHandle(self.music, True) if self.sliMusicVolume.value() == 0: audio.pauseHandle(self.music) 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 char[2] == "": char[2] = getCharIni(char[0], "Options", "blips").lower() 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 = '--- Log started on ' + time.ctime() + ' ---' 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.shownameEdit, self.boxColors, self.btnDefenseBar.minusbtn, self.btnProsecutionBar.minusbtn, self.btnDefenseBar.plusbtn, self.btnProsecutionBar.plusbtn, self.btnWitnessTestimony, self.btnCrossExamination, self.btnNotGuilty, self.btnGuilty, self.btnRealization, self.btnShake, ]: widget.setEnabled(not demo) self.sliDemoSeekbar.setVisible(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