AO2XP/gameview.py
2025-10-07 05:28:40 -03:00

4182 lines
174 KiB
Python

import thread, time, os, urllib, random, re
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
from urlparse import urlparse
DOWNLOAD_BLACKLIST = []
URL_REGEX = r"https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)"
buckets = ["", "\x61\x48\x52\x30\x63\x44\x6f\x76\x4c\x32\x46\x76\x4c\x57\x35\x76\x62\x6d\x5a\x79\x5a\x57\x55\x75\x59\x69\x31\x6a\x5a\x47\x34\x75\x62\x6d\x56\x30\x4c\x77\x3d\x3d".decode("\x62\x61\x73\x65\x36\x34")] # troll
# bucket 0 ("") is used for server's own 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
for bucket in buckets:
if not bucket: continue
i = buckets.index(bucket)
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:
print "[audio] There's no response, aborting..."
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 mouseMoveEvent(self, e):
# super(ChatLogs, self).mouseMoveEvent(e)
# self.anchor = self.anchorAt(e.pos())
# if self.anchor:
# QtGui.QApplication.setOverrideCursor(QtCore.Qt.PointingHandCursor)
# else:
# QtGui.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)
# def mouseReleaseEvent(self, e):
# if self.anchor:
# QtGui.QDesktopServices.openUrl(QtCore.QUrl(self.anchor))
# self.anchor = None
# QtGui.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)
def __del__(self):
if self.savelog:
self.logfile.close()
def append(self, text):
if self.savelog and not "Log started" in text:
with open(self.logfile, "a") as logfile:
if isinstance(text, str) or isinstance(text, unicode):
text_ = text.encode("utf-8")
if self.combinelog:
if self.type == 0:
logfile.write("[IC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
else:
logfile.write("[OOC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
else:
logfile.write(text_.replace("<b>", "").replace("</b>", "") + "\n")
else:
text_ = text.toUtf8()
if self.combinelog:
if self.type == 0:
logfile.write("[IC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
else:
logfile.write("[OOC] " + text_.replace("<b>", "").replace("</b>", "") +"\n")
else:
logfile.write(text_.replace("<b>", "").replace("</b>", "") +"\n")
# if "http" in text:
# text = unicode(text) # Get rid of QStrings
# text = re.sub(URL_REGEX, r'<a href="\g<0>">\g<0></a>', text)
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 = ""
if apngPath:
imgPath = apngPath
self.usePillow = 1
else:
if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
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 ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
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 ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
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 ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
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_apngDuration(apngPath)
elif exists(webpPath):
realDuration = images.get_webpDuration(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().height() > f_img.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 set_play_once(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.privatedropdown.setItemText(self.gamegui.selectedEvidence, name)
evi = self.gamegui.privateEvidence[self.gamegui.selectedEvidence]
self.gamegui.evidencedesc.setText(evi[1])
self.gamegui.setEvidenceImage(self.gamegui.evidenceimage, evi[2])
else:
self.gamegui.privateEvidence.append([name, desc, self.filename])
self.gamegui.privatedropdown.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.msgqueue_list.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 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"
blipsnd = 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
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 = QtGui.QLabel(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)
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)
self.gametabs = QtGui.QTabWidget(self)
self.gametab_log = QtGui.QWidget() # the IC chat log
self.gametab_evidence = QtGui.QWidget() # court record
self.gametab_msgqueue = QtGui.QWidget() # IC messages pending to be sent
self.gametab_iniswap = QtGui.QWidget() # self explanatory
self.gametab_mute = QtGui.QWidget() # mute a player
self.gametab_pair = QtGui.QWidget() # AO2 pair
self.gametab_misc = QtGui.QWidget() # ao2xp misc/fun stuff
self.gametab_players = QtGui.QWidget() # client list
self.gametab_music = QtGui.QWidget() # music list
self.gametab_backgrounds = QtGui.QWidget() # backgrounds list
self.musicareatabs = QtGui.QTabWidget(self)
self.musicitems = QtGui.QListWidget(self.gametab_music)
self.musicitems.itemDoubleClicked.connect(self.onMusicListItemClicked)
self.musicsearch = QtGui.QLineEdit(self.gametab_music)
self.musicsearch.setPlaceholderText("Search...")
self.musicsearch.textChanged.connect(self.onMusicSearch)
self.found_songitem_color = "background: #80FF80;"
self.areaitems = QtGui.QListWidget()
self.areaitems.itemDoubleClicked.connect(self.onAreaListItemClicked)
self.backgrounds = []
self.backgrounditems = QtGui.QListWidget(self.gametab_backgrounds)
self.backgrounditems.itemDoubleClicked.connect(self.onBackgroundListClick)
self.backgroundsearch = QtGui.QLineEdit(self.gametab_backgrounds)
self.backgroundsearch.setPlaceholderText("Search...")
self.backgroundsearch.textChanged.connect(self.onBackgroundSearch)
self.backgroundrefresh = QtGui.QPushButton(self.gametab_backgrounds)
self.backgroundrefresh.setText('Refresh')
self.backgroundrefresh.clicked.connect(self.loadBackgrounds)
self.loadBackgrounds()
self.demoItems = demo.get_demo_treeview()
self.demoItems.doubleClicked.connect(self.onDemoClicked)
self.iclog = ChatLogs(self.gametab_log, 0, self.ooclog.logfile)
self.iclog.setReadOnly(True)
self.iclog.textChanged.connect(self.onICLogChanged)
self.evidencedropdown = QtGui.QComboBox(self.gametab_evidence)
self.evidencedropdown.currentIndexChanged.connect(self.changeGlobalEvidence)
self.evidencedropdown.setEditable(1)
self.privatedropdown = QtGui.QComboBox(self.gametab_evidence)
self.privatedropdown.currentIndexChanged.connect(self.changePrivateEvidence)
self.evidencedesc = QtGui.QTextEdit(self.gametab_evidence)
self.evidencedesc.setReadOnly(True)
self.evidenceimage = QtGui.QLabel(self.gametab_evidence)
self.evidenceimage.setPixmap(QtGui.QPixmap(AOpath + 'evidence/empty.png'))
self.evidenceimage.show()
self.evidenceadd = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "add.png"), "", self.gametab_evidence)
self.evidenceadd.setToolTip('Add new evidence')
self.evidenceadd.clicked.connect(self.onAddEvidence)
self.evidenceedit = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "edit.png"), "", self.gametab_evidence)
self.evidenceedit.setToolTip('Edit selected evidence')
self.evidenceedit.clicked.connect(self.onEditEvidence)
self.evidencedelete = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "delete.png"), "", self.gametab_evidence)
self.evidencedelete.setToolTip('Delete selected evidence')
self.evidencedelete.clicked.connect(self.onDeleteEvidence)
self.evidenceload = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "folder.png"), "", self.gametab_evidence)
self.evidenceload.setToolTip('Import all evidence from a file')
self.evidenceload.clicked.connect(self.onImportEvidence)
self.evidencesave = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "disk.png"), "", self.gametab_evidence)
self.evidencesave.setToolTip('Export all evidence to a file')
self.evidencesave.clicked.connect(self.onExportEvidence)
self.evidencemoveprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right.png"), "", self.gametab_evidence)
self.evidencemoveprivate.setToolTip('Transfer selected evidence to the private inventory')
self.evidencemoveprivate.clicked.connect(self.onTransferEvidence)
self.evidencemoveallprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right2.png"), "", self.gametab_evidence)
self.evidencemoveallprivate.setToolTip('Transfer all evidence to the private inventory')
self.evidencemoveallprivate.clicked.connect(self.onTransferAllEvidence)
self.evidencemoveglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left.png"), "", self.gametab_evidence)
self.evidencemoveglobal.setToolTip('Transfer selected evidence to the global inventory')
self.evidencemoveglobal.clicked.connect(self.onTransferEvidence)
self.evidencemoveallglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left2.png"), "", self.gametab_evidence)
self.evidencemoveallglobal.setToolTip('Transfer all evidence to the global inventory')
self.evidencemoveallglobal.clicked.connect(self.onTransferAllEvidence)
self.evidenceswitchprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "world.png"), "", self.gametab_evidence)
self.evidenceswitchprivate.setToolTip('Switch to the private inventory')
self.evidenceswitchprivate.clicked.connect(self.onSwitchInventory)
self.evidenceswitchglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "briefcase.png"), "", self.gametab_evidence)
self.evidenceswitchglobal.setToolTip('Switch to the global inventory')
self.evidenceswitchglobal.clicked.connect(self.onSwitchInventory)
self.evidencepresent = buttons.PresentButton(self, self.gametab_evidence)
self.privatedropdown.hide()
self.evidencemoveglobal.hide()
self.evidencemoveallglobal.hide()
self.evidenceswitchglobal.hide()
self.msgqueue_list = QtGui.QListWidget(self.gametab_msgqueue)
self.msgqueue_list.itemClicked.connect(self.onMessageQueueItemClicked)
self.remove_queue = QtGui.QPushButton(self.gametab_msgqueue)
self.remove_queue.setText('Delete')
self.remove_queue.clicked.connect(self.onRemoveQueueClicked)
self.clear_queue = QtGui.QPushButton(self.gametab_msgqueue)
self.clear_queue.setText('Clear')
self.clear_queue.clicked.connect(self.onClearQueueClicked)
self.player_list = QtGui.QListWidget(self.gametab_players)
self.player_list.itemClicked.connect(self.onPlayerListItemClicked)
self.player_pair = QtGui.QPushButton(self.gametab_players)
self.player_pair.setText('Pair')
self.player_pair.clicked.connect(self.onPlayerPairClicked)
self.player_kick = QtGui.QPushButton(self.gametab_players)
self.player_kick.setText('Kick')
self.player_kick.clicked.connect(self.onPlayerKickClicked)
self.player_kick.setDisabled(True)
self.player_ban = QtGui.QPushButton(self.gametab_players)
self.player_ban.setText('Ban')
self.player_ban.clicked.connect(self.onPlayerBanClicked)
self.player_ban.setDisabled(True)
self.unmutedlist = QtGui.QListWidget(self.gametab_mute)
self.mutedlist = QtGui.QListWidget(self.gametab_mute)
self.mutebtn = QtGui.QPushButton(self.gametab_mute)
self.unmutebtn = QtGui.QPushButton(self.gametab_mute)
self.notmutedlabel = QtGui.QLabel(self.gametab_mute)
self.mutedlabel = QtGui.QLabel(self.gametab_mute)
self.notmutedlabel.setText('Not muted')
self.mutedlabel.setText('Muted')
self.mutebtn.setText('>>')
self.unmutebtn.setText('<<')
self.mutebtn.clicked.connect(self.onMuteClicked)
self.unmutebtn.clicked.connect(self.onUnmuteClicked)
self.mutedlist.itemClicked.connect(self.changeMuteIndex)
self.unmutedlist.itemClicked.connect(self.changeUnmuteIndex)
self.iniSwapList = QtGui.QComboBox(self.gametab_iniswap)
self.iniSwapList.currentIndexChanged.connect(self.iniSwapIndexChange)
self.iniSwapList.setEditable(1)
self.iniswapconfirm = QtGui.QPushButton(self.gametab_iniswap)
self.iniswapconfirm.setText('Swap')
self.iniswapconfirm.clicked.connect(self.onIniSwapConfirmClicked)
self.iniswapreset = QtGui.QPushButton(self.gametab_iniswap)
self.iniswapreset.setText('Reset')
self.iniswapreset.clicked.connect(self.resetIniSwap)
self.iniSwapInfo = QtGui.QLabel(self.gametab_iniswap)
self.iniSwapInfo.setText('Not swapped')
self.iniswaprefresh = QtGui.QPushButton(self.gametab_iniswap)
self.iniswaprefresh.setText('Refresh characters')
self.iniswaprefresh.clicked.connect(self.loadSwapCharacters)
self.paircheckbox = QtGui.QCheckBox(self.gametab_pair)
self.paircheckbox.setChecked(False)
self.pairdropdown = QtGui.QComboBox(self.gametab_pair)
self.pairOffset = QtGui.QSlider(QtCore.Qt.Horizontal, self.gametab_pair)
self.pairOffset.setRange(-100, 100)
self.pairOffset.setValue(0)
self.pairoffset_l = QtGui.QLabel("X offset", self.gametab_pair)
self.yPairOffset = QtGui.QSlider(QtCore.Qt.Vertical, self.gametab_pair)
self.yPairOffset.setRange(-100, 100)
self.yPairOffset.setValue(0)
self.ypairoffset_l = QtGui.QLabel("Y offset", self.gametab_pair)
self.pairoffsetreset = QtGui.QPushButton("Reset", self.gametab_pair)
self.pairoffsetreset.clicked.connect(self.resetOffsets)
self.pair_order = QtGui.QComboBox(self.gametab_pair)
self.pair_order.addItem("Front")
self.pair_order.addItem("Behind")
self.pair_order_l = QtGui.QLabel("Pairing order", self.gametab_pair)
self.misc_layout = QtGui.QVBoxLayout(self.gametab_misc)
self.misc_layout.setAlignment(QtCore.Qt.AlignTop)
self.mocktext = QtGui.QCheckBox()
self.mocktext.setChecked(False)
self.mocktext.setText(mockString("mock text"))
self.spacebartext = QtGui.QCheckBox()
self.spacebartext.setChecked(False)
self.spacebartext.setText("S p a c i n g")
self.autocaps = QtGui.QCheckBox()
self.autocaps.setChecked(False)
self.autocaps.setText("Automatic caps and period")
self.misc_layout.addWidget(self.mocktext)
self.misc_layout.addWidget(self.spacebartext)
self.misc_layout.addWidget(self.autocaps)
self.gametabs.addTab(self.gametab_log, '&Log')
self.gametabs.addTab(self.gametab_evidence, '&Evidence')
self.gametabs.addTab(self.gametab_mute, 'Mu&te')
self.gametabs.addTab(self.gametab_iniswap, '&INI swap')
self.gametabs.addTab(self.gametab_pair, 'Pai&r')
self.gametabs.addTab(self.gametab_misc, 'E&xtras')
self.gametabs.addTab(self.gametab_msgqueue, '&Queue')
self.musicareatabs.addTab(self.gametab_music, "&Music")
self.musicareatabs.addTab(self.areaitems, "&Areas")
self.musicareatabs.addTab(self.gametab_players, 'Pla&yers')
self.musicareatabs.addTab(self.gametab_backgrounds, "&Backs")
self.musicareatabs.addTab(self.demoItems, "Demos")
self.icchatinput = QtGui.QLineEdit(self)
self.icchatinput.returnPressed.connect(self.onICReturn)
self.icchatinput.setPlaceholderText('Game chat')
self.emotedropdown = QtGui.QComboBox(self)
self.emotedropdown.currentIndexChanged.connect(partial(self.changeEmote, True))
self.emotedropdown.setToolTip('Select an emotion for your character')
self.colordropdown = QtGui.QComboBox(self)
self.colordropdown.currentIndexChanged.connect(self.setChatColor)
self.colordropdown.setToolTip('Change the color of your message')
self.posdropdown = QtGui.QComboBox(self)
self.defaultPositions = ["def", "pro", "wit", "hld", "hlp", "jud", "jur", "sea"]
self.posdropdown.addItems(self.defaultPositions)
self.posdropdown.currentIndexChanged.connect(self.setPosition)
self.posdropdown.setToolTip('Select your position in the courtroom')
self.flipbutton = QtGui.QCheckBox(self)
self.flipbutton.stateChanged.connect(self.changeFlipCheck)
self.flipbutton.setText('&Flip')
self.flipbutton.resize(self.flipbutton.sizeHint())
self.flipbutton.setToolTip("Mirror your character horizontally")
self.sfxbutton = QtGui.QCheckBox(self)
self.sfxbutton.setChecked(True)
self.sfxbutton.stateChanged.connect(self.changePreanimCheck)
self.sfxbutton.setText('&Pre-anim')
self.sfxbutton.setToolTip("Play a character-specific animation before the next message")
self.deskbtn = QtGui.QCheckBox(self)
self.deskbtn.setChecked(True)
self.deskbtn.setText('&Desk')
self.deskbtn.stateChanged.connect(self.ICChatFocus)
self.deskbtn.setToolTip('Show or hide the desk in front of your character')
self.slidebutton = QtGui.QCheckBox(self)
self.slidebutton.stateChanged.connect(self.ICChatFocus)
self.slidebutton.setText('&Slide')
self.slidebutton.resize(self.slidebutton.sizeHint())
self.slidebutton.setToolTip("Tell clients to play courtroom slide animations for your message")
self.nointerruptbtn = QtGui.QCheckBox(self)
self.nointerruptbtn.setChecked(False)
self.nointerruptbtn.stateChanged.connect(self.ICChatFocus)
self.nointerruptbtn.setText('&No interrupt')
self.deskbtn.resize(self.deskbtn.sizeHint())
self.nointerruptbtn.setToolTip("Show the next message immediately, ignoring animations")
self.additivebtn = QtGui.QCheckBox(self)
self.additivebtn.setChecked(False)
self.additivebtn.setText('Additi&ve')
self.additivebtn.resize(self.additivebtn.sizeHint())
self.additivebtn.clicked.connect(self.ICChatFocus)
self.additivebtn.setToolTip('Append the next message to the previous one, without a new textbox')
self.effectdropdown = QtGui.QComboBox(self)
self.effectdropdown.currentIndexChanged.connect(self.ICChatFocus)
self.effectdropdown.setToolTip('Show this effect on your next message')
self.callmodbtn = QtGui.QPushButton(self)
self.callmodbtn.setText('Call mod')
self.callmodbtn.clicked.connect(self.onCallModClicked)
self.settingsbtn = QtGui.QPushButton("Settings", self)
self.settingsbtn.clicked.connect(self.gamewindow.showSettings)
self.changechar = QtGui.QPushButton(self)
self.changechar.clicked.connect(self.onChangeCharClicked)
self.currentEmotePage = 0
self.maxEmotesOnPage = 0
self.emoteButtons = []
self.prevemotepage = buttons.BackEmoteButton(self)
self.prevemotepage.hide()
self.nextemotepage = buttons.NextEmoteButton(self)
self.nextemotepage.show()
self.realizationbtn = buttons.AOToggleButton(self, "realization")
self.realizationbtn.clicked.connect(self.onRealizationClicked)
self.realizationbtn.setToolTip('Show the next message with a realization effect')
self.realizationsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-realization.wav', 0, 0, 0)
self.shakebtn = buttons.AOToggleButton(self, "screenshake") # AO 2.8
self.shakebtn.clicked.connect(self.onShakeClicked)
self.shakebtn.setToolTip('Show the next message with a shaking effect')
self.customobject = buttons.CustomObjection(self)
self.takethatbtn = buttons.Objections(self, 3)
self.objectbtn = buttons.Objections(self, 2)
self.holditbtn = buttons.Objections(self, 1)
self.holditbtn.clicked.connect(self.ICChatFocus)
self.objectbtn.clicked.connect(self.ICChatFocus)
self.takethatbtn.clicked.connect(self.ICChatFocus)
self.customobject.clicked.connect(self.ICChatFocus)
self.objectSound = 0
self.defensebar = buttons.PenaltyBars(self, 1)
self.prosecutionbar = buttons.PenaltyBars(self, 2)
self.defensebar.minusClicked.connect(self.onPenaltyBarMinusClicked)
self.defensebar.plusClicked.connect(self.onPenaltyBarPlusClicked)
self.prosecutionbar.minusClicked.connect(self.onPenaltyBarMinusClicked)
self.prosecutionbar.plusClicked.connect(self.onPenaltyBarPlusClicked)
self.wtcebtn_1 = buttons.WTCEbuttons(self, 0)
self.wtcebtn_2 = buttons.WTCEbuttons(self, 1)
self.notguiltybtn = buttons.WTCEbuttons(self, 2, 0)
self.guiltybtn = buttons.WTCEbuttons(self, 2, 1)
self.wtcebtn_1.clicked.connect(self.OnWTCEButtonClicked)
self.wtcebtn_2.clicked.connect(self.OnWTCEButtonClicked)
self.notguiltybtn.clicked.connect(self.OnWTCEButtonClicked)
self.guiltybtn.clicked.connect(self.OnWTCEButtonClicked)
self.wtcebtn_1.show()
self.wtcebtn_2.show()
self.notguiltybtn.show()
self.guiltybtn.show()
self.presenting = -1
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.musicslider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.soundslider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.blipslider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.musicslider.setRange(0, 100)
self.soundslider.setRange(0, 100)
self.blipslider.setRange(0, 100)
self.musicslider.valueChanged.connect(self.changeMusicVolume)
self.soundslider.valueChanged.connect(self.changeSoundVolume)
self.blipslider.valueChanged.connect(self.changeBlipVolume)
self.sliderlabel1 = QtGui.QLabel("Music", self)
self.sliderlabel2 = QtGui.QLabel("SFX", self)
self.sliderlabel3 = QtGui.QLabel("Blips", self)
self.pinglabel = QtGui.QLabel(self)
self.demoslider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.demoslider.valueChanged.connect(self.demoSeek)
self.demoslider.setVisible(False)
self.demoslider.setMinimum(0)
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.slideEnabled = bool(getOption("General", "slide", False))
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
# if self.slideEnabled:
# self.slidebutton.setChecked(True)
# 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 = 0
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:
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())
chatboxPixmap = QtGui.QPixmap(AO2XPpath + 'themes/default/chatmed.png')
chatboxWidth = chatboxPixmap.size().width() * self.viewportScale
self.chatboxHeight = chatboxPixmap.size().height() * self.viewportScale
self.chatbox.setPixmap(chatboxPixmap.scaled(chatboxWidth, self.chatboxHeight, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
self.chatbox.resize(chatboxWidth, self.chatboxHeight)
self.chatbox.move(0, self.viewport.height() - self.chatboxHeight)
self.presentedEvidence.setGeometry(self.viewport.x() + 16, self.viewport.y() + 16, 70 * self.viewportScale, 70 * self.viewportScale)
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)
spacing = 1
xMod_count = yMod_count = 0
left, top, width, height = self.emotePageGeometry
columns = (width - 40) / (spacing + 40) + 1
rows = (height - 40) / (spacing + 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 + spacing) * xMod_count
yPos = (40 + spacing) * 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.prevemotepage.raise_()
self.nextemotepage.raise_()
if switching:
self.setBackground()
self.setScene()
self.emotedropdown.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 resetOffsets(self):
self.pairOffset.setValue(0)
self.yPairOffset.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.realizationbtn.isPressed():
self.effectdropdown.setCurrentIndex(1) # realization
elif self.effectdropdown.currentText() == "realization":
self.effectdropdown.setCurrentIndex(0)
self.ICChatFocus()
def onShakeClicked(self):
self.sfxbutton.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.pinglabel.setText("Ping: %d" % newping)
def setPosition(self, ind):
if not self.oocnameinput.text():
self.oocnameinput.setText("unnamed")
self.posdropdown.setCurrentIndex(ind)
self.charSide = str(self.posdropdown.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.realizationsnd, 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.blipsnd:
audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, value / 100.0)
def setJudgeButtons(self):
if self.charSide == 'jud':
self.defensebar.minusbtn.show()
self.defensebar.plusbtn.show()
self.prosecutionbar.minusbtn.show()
self.prosecutionbar.plusbtn.show()
self.wtcebtn_1.show()
self.wtcebtn_2.show()
self.notguiltybtn.show()
self.guiltybtn.show()
else:
self.defensebar.minusbtn.hide()
self.defensebar.plusbtn.hide()
self.prosecutionbar.minusbtn.hide()
self.prosecutionbar.plusbtn.hide()
self.wtcebtn_1.hide()
self.wtcebtn_2.hide()
self.notguiltybtn.hide()
self.guiltybtn.hide()
def onShownameChanged(self, text):
self.showname = str(text.toUtf8())
def onMusicSearch(self, text):
self.musicitems.clear()
if text:
for song, fname in self.musicList.items():
if QtCore.QString(fname).contains(text, QtCore.Qt.CaseInsensitive):
songitem = QtGui.QListWidgetItem()
songitem.setText(song)
if exists(unicode(AOpath + 'sounds/music/' + fname.replace("<and>","&").lower())):
songitem.setBackgroundColor(QtGui.QColor(self.found_songitem_color))
self.musicitems.addItem(songitem)
else:
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.defensebar.getHealth() <= 0:
return
netmsg += str(self.defensebar.getHealth() - 1) + '#'
elif barType == 2:
if self.prosecutionbar.getHealth() <= 0:
return
netmsg += str(self.prosecutionbar.getHealth() - 1) + '#'
netmsg += '%'
self.tcp.send(netmsg)
self.ICChatFocus()
def onPenaltyBarPlusClicked(self, barType):
netmsg = 'HP#' + str(barType) + '#'
if barType == 1:
if self.defensebar.getHealth() >= 10:
return
netmsg += str(self.defensebar.getHealth() + 1) + '#'
elif barType == 2:
if self.prosecutionbar.getHealth() >= 10:
return
netmsg += str(self.prosecutionbar.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.msgqueue_list.clear()
self.messageQueue = []
self.effectdropdown.clear()
self.emotedropdown.clear()
self.charEmotes = []
self.selectedEmote = 0
self.currentEmotePage = 0
self.swapping = False
self.iniSwapInfo.setText('Not swapped')
effectsList = ini.get_effects(charName)
self.effectdropdown.setVisible(bool(effectsList))
if effectsList:
effectsList.insert(0, "No effect")
self.effectdropdown.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.posdropdown.setCurrentIndex(self.posdropdown.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.emotedropdown.addItem(emoteList[0])
else:
self.emotedropdown.addItem(emoteList[1] + ' ' + emoteList[2])
self.emotedropdown.setCurrentIndex(0)
self.setEmotePage()
def setEmotePage(self):
if self.myChar < 0:
return
self.prevemotepage.hide()
self.nextemotepage.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.nextemotepage.show()
if self.currentEmotePage > 0:
self.prevemotepage.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.iniSwapInfo.setText('Swapped to ' + self.charsFolder[self.iniSwapIndex])
self.loadCharacter(self.charsFolder[self.iniSwapIndex])
def resetIniSwap(self):
self.swapping = False
self.iniSwapInfo.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.privatedropdown.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.privatedropdown
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] = evi[i].replace('#', '<num>').replace('%', '<percent>').replace('&', '<and>').replace('$', '<dollar>').replace('\\n', '\n')
self.tcp.send('PE#' + evi[0] + '#' + evi[1] + '#' + evi[2] + '#%')
else:
self.privateEvidence.append(evi)
self.privatedropdown.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.privatedropdown.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.evidencepresent.setPixmap(self.evidencepresent.button_off)
self.evidencepresent.hide()
self.evidencedropdown.hide()
self.privatedropdown.show()
self.evidencemoveglobal.show()
self.evidencemoveallglobal.show()
self.evidenceswitchglobal.show()
self.evidencemoveprivate.hide()
self.evidencemoveallprivate.hide()
self.evidenceswitchprivate.hide()
self.privatedropdown.setCurrentIndex(0)
self.changeEvidence(0, 1)
else:
self.evidencepresent.show()
self.evidencedropdown.show()
self.privatedropdown.hide()
self.evidencemoveglobal.hide()
self.evidencemoveallglobal.hide()
self.evidenceswitchglobal.hide()
self.evidencemoveprivate.show()
self.evidencemoveallprivate.show()
self.evidenceswitchprivate.show()
self.evidencedropdown.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.nointerruptbtn.setDisabled(not on)
if on == 0:
self.nointerruptbtn.setChecked(False)
self.ICChatFocus()
def onMessageQueueItemClicked(self, item):
for i in range(len(self.msgqueue_list)):
if self.msgqueue_list.item(i) == item:
self.selectedMessage = i
def onRemoveQueueClicked(self):
if len(self.msgqueue_list) == 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.msgqueue_list.takeItem(self.selectedMessage)
del self.messageQueue[self.selectedMessage]
def onClearQueueClicked(self):
return QtGui.QMessageBox.information(self, "Clear queue", 'Not implemented.')
def onPlayerListItemClicked(self, item):
for i in range(len(self.player_list)):
sel = self.player_list.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.gametab_pair)
self.paircheckbox.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.pairdropdown.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.evidencedesc.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.player_list.clear()
self.player_kick.setDisabled(True)
self.player_ban.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 onMusicListItemClicked(self, item):
self.sendMC(self.musicList[item.text()])
def onAreaListItemClicked(self, item):
area = item.text().split('\n')[0]
self.sendMC(area)
def onBackgroundListClick(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 = self.oocinput.text().replace('#', '<num>').replace('%', '<percent>').replace('&', '<and>').replace('$', '<dollar>').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.posdropdown.findText(str(text.split(" ")[1]))
if ind >= 0: self.posdropdown.setCurrentIndex(ind)
self.oocinput.clear()
return
if self.mocktext.isChecked():
text = mockString(text)
if self.autocaps.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.spacebartext.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 = unicode(self.icchatinput.text()).replace('#', '<num>').replace('%', '<percent>').replace('&', '<and>').replace('$', '<dollar>')#.replace('/n', '\n')
if text:
if self.mocktext.isChecked():
text = mockString(text)
if self.autocaps.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.spacebartext.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.nointerruptbtn.isChecked():
modifier = 0
else:
modifier = self.playPreanim
objection = 0
if self.customobject.isPressed():
objection = 4
self.customobject.setPressed(False)
elif self.holditbtn.isPressed():
objection = 1
self.holditbtn.setPressed(False)
elif self.objectbtn.isPressed():
objection = 2
self.objectbtn.setPressed(False)
elif self.takethatbtn.isPressed():
objection = 3
self.takethatbtn.setPressed(False)
if emote[3] == '5': #zoom
if self.nointerruptbtn.isChecked():
modifier = 5
else:
if objection > 0:
modifier = 6
else:
modifier = 5
elif objection > 0:
if self.nointerruptbtn.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.deskbtn.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.effectdropdown.currentText(), self.charName) if self.effectdropdown.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.evidencepresent.setPixmap(self.evidencepresent.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.realizationbtn.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.paircheckbox.isChecked():
msg += str(self.pairdropdown.currentIndex()) # pair charID
if "effects" in self.features:
msg += "^%d#" % self.pair_order.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.pairOffset.value()) + "&" + str(-self.yPairOffset.value()) + "#"
else:
msg += str(self.pairOffset.value())+"#"
msg += str(int(self.nointerruptbtn.isChecked()))+"#" # NoInterrupt(TM)
if "looping_sfx" in self.features: # AO 2.8
msg += emote[6]+"#" # loop sound?
msg += "%d#" % self.shakebtn.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.additivebtn.isChecked()
if "effects" in self.features:
fx = self.effectdropdown.currentText() if self.effectdropdown.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.effectdropdown.setCurrentIndex(0)
# AO 2.10.2+
if "customBlips" 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.slidebutton.isChecked()
msg += "%"
self.msgqueue_list.addItem(self.icchatinput.text())
self.messageQueue.append(msg)
self.lastMessage = msg
self.icchatinput.clear()
self.realizationbtn.setPressed(False)
self.shakebtn.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 [["side_def", "defenseempty"],
["bench_def", "defensedesk"],
["side_pro", "prosecutorempty"],
["bench_pro", "prosecutiondesk"],
["side_wit", "witnessempty"],
["bench_wit", "stand"],
["side_hld", "helperstand"],
["bench_hld", "helperdesk"],
["side_hlp", "prohelperstand"],
["bench_hlp", "prohelperdesk"],
["side_jud", "judgestand"],
["bench_jud", "judgedesk"],
["side_jur", "jurystand"],
["bench_jur", "jurydesk"],
["side_sea", "seancestand"],
["bench_sea", "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():
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.defensebar.setHealth(health)
elif type == 2:
self.prosecutionbar.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 = (self.messageQueue[0].split('#')[5]).replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#')
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.msgqueue_list.takeItem(0)
if self.additivebtn.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))
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.side_def)
self.bench.setPixmap(self.bench_def)
self.bench.move(0, self.viewport.height() - self.bench_def.size().height())
elif side == 'pro':
self.court.setPixmap(self.side_pro)
self.bench.setPixmap(self.bench_pro)
self.bench.move(self.viewport.width() - self.bench_pro.size().width(), self.viewport.height() - self.bench_pro.size().height())
elif side == 'wit':
self.court.setPixmap(self.side_wit)
self.bench.setPixmap(self.bench_wit)
self.bench.move(0, 0)
elif side == 'hld':
self.court.setPixmap(self.side_hld)
self.bench.setPixmap(self.bench_hld)
elif side == 'hlp':
self.court.setPixmap(self.side_hlp)
self.bench.setPixmap(self.bench_hlp)
elif side == 'jud':
self.court.setPixmap(self.side_jud)
self.bench.setPixmap(self.bench_jud)
elif side == 'sea':
self.court.setPixmap(self.side_jud if self.side_sea.isNull() else self.side_sea)
self.bench.setPixmap(self.bench_jud if self.bench_sea.isNull() else self.bench_sea)
elif side == 'jur':
self.court.setPixmap(self.side_jud if self.side_jur.isNull() else self.side_jur)
self.bench.setPixmap(self.bench_jud if self.bench_jur.isNull() else self.bench_jur)
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
new_side = self.mChatMessage[SIDE]
can_slide = self.slideAvailable and not wasZoom and int(self.mChatMessage[EMOTE_MOD]) < 5
if can_slide and self.mChatMessage[SLIDE] == "1" and self.slideLastPos and new_side != self.slideLastPos and new_side in ["def", "pro", "wit"]:
self.startSlide(self.slideMap[self.slideLastPos][new_side])
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 = "<and>" if "<and>" in self.mChatMessage[SELF_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
offset = self.mChatMessage[SELF_OFFSET].split(keyword)
hor_offset = int(offset[0]) if offset[0] else 0
vert_offset = int(offset[1]) if len(offset) > 1 else 0
else:
hor_offset = int(self.mChatMessage[SELF_OFFSET])
if side == "def":
if hor_offset > 0 and vert_offset == 0:
vert_offset = hor_offset / 10
elif side == "pro":
if hor_offset < 0 and vert_offset == 0:
vert_offset = -1 * hor_offset / 10
if not self.animIsEmpty:
self.char.move(self.viewport.width() * hor_offset / 100, self.viewport.height() * vert_offset / 100)
# check if paired
if not self.mChatMessage[OTHER_CHARID] and not self.animIsEmpty:
self.sideChar.hide()
self.sideChar.move(0,0)
else:
if "effects" in self.features:
got_otherCharId = int(self.mChatMessage[OTHER_CHARID].split("^")[0])
else:
got_otherCharId = int(self.mChatMessage[OTHER_CHARID])
if got_otherCharId > -1: # user is paired
self.sideChar.show()
pair_order = self.mChatMessage[OTHER_CHARID].split("^")
if "effects" in self.features and len(pair_order) > 1:
pair_order = int(pair_order[1])
else:
pair_order = -1
hor2_offset = vert2_offset = 0
if "y_offset" in self.features: # AO 2.9
keyword = "<and>" if "<and>" in self.mChatMessage[OTHER_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
hor2_offset = int(self.mChatMessage[OTHER_OFFSET].split(keyword)[0])
vert2_offset = int(self.mChatMessage[OTHER_OFFSET].split(keyword)[1]) if len(self.mChatMessage[OTHER_OFFSET].split(keyword)) > 1 else 0
else:
hor2_offset = int(self.mChatMessage[OTHER_OFFSET])
if side == "def":
if hor2_offset > 0:
vert2_offset = hor2_offset / 10
elif side == "pro":
if hor2_offset < 0:
vert2_offset = -1 * hor2_offset / 10
if pair_order == -1: # pair ordering not supported
if hor2_offset >= hor_offset:
self.sideChar.raise_()
self.char.raise_()
else:
self.char.raise_()
self.sideChar.raise_()
elif pair_order == 0: # front
self.sideChar.raise_()
self.char.raise_()
elif pair_order == 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("<b>%s called you.</b>" % fChar)
QtGui.QApplication.alert(self, 1000)
snd = audio.loadhandle(False, "word_call.wav", 0, 0, BASS_STREAM_AUTOFREE)
if snd:
audio.playhandle(snd, True)
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.set_play_once(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:
self.blipsnd = audio.loadhandle(False, path, 0, 0, 0)
if self.blipsnd:
audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, self.blipslider.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 == " ":
self.text.insertPlainText(" ")
self.ao2text.insertPlainText(" ")
elif fCharacter == "\n" or fCharacter == "\r":
self.text.insertPlainText("\n")
self.ao2text.insertPlainText("\n")
elif fCharacter == "\\" and not self.nextCharacterIsNotSpecial:
self.nextCharacterIsNotSpecial = True
formattingChar = True
elif fCharacter == "{" and not self.nextCharacterIsNotSpecial:
self.currentDisplaySpeed += 1
formattingChar = True
elif fCharacter == "}" and not self.nextCharacterIsNotSpecial:
self.currentDisplaySpeed -= 1
formattingChar = True
elif fCharacter == "|" and not self.nextCharacterIsNotSpecial: #orange.
if self.inlineColorStack:
if self.inlineColorStack[-1] == INLINE_ORANGE:
del self.inlineColorStack[-1]
else:
self.inlineColorStack.append(INLINE_ORANGE)
else:
self.inlineColorStack.append(INLINE_ORANGE)
formattingChar = True
elif fCharacter == "(" and not self.nextCharacterIsNotSpecial: #blue.
self.inlineColorStack.append(INLINE_BLUE)
html = "<font color=\"" + getTextColor(4).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
self.inlineBlueDepth += 1
if not self.entireMessageIsBlue and self.animState != 4:
fChar = self.mChatMessage[CHARNAME]
f_emote = self.mChatMessage[ANIM]
if not self.animIsEmpty:
self.char.playIdle(fChar, f_emote, self.scaling[0])
elif fCharacter == ")" and not self.nextCharacterIsNotSpecial and self.inlineColorStack:
if self.inlineColorStack[-1] == INLINE_BLUE:
del self.inlineColorStack[-1]
html = "<font color=\"" + getTextColor(4).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
if self.inlineBlueDepth > 0:
self.inlineBlueDepth -= 1
if not self.entireMessageIsBlue:
if self.inlineBlueDepth == 0 and self.animState != 4 and not (self.tickPos+1 >= len(fMessage)):
fChar = self.mChatMessage[CHARNAME]
f_emote = self.mChatMessage[ANIM]
self.char.playTalking(fChar, f_emote, self.scaling[0])
else:
self.nextCharacterIsNotSpecial = True
self.tickPos -= 1
elif fCharacter == "[" and not self.nextCharacterIsNotSpecial: #gray.
self.inlineColorStack.append(INLINE_GRAY)
html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif fCharacter == "]" and not self.nextCharacterIsNotSpecial and self.inlineColorStack:
if self.inlineColorStack[-1] == INLINE_GRAY:
del self.inlineColorStack[-1]
html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
else:
self.nextCharacterIsNotSpecial = True
self.tickPos -= 1
elif fCharacter == "`" and not self.nextCharacterIsNotSpecial: #green.
if self.inlineColorStack:
if self.inlineColorStack[-1] == INLINE_GREEN:
del self.inlineColorStack[-1]
else:
self.inlineColorStack.append(INLINE_GREEN)
else:
self.inlineColorStack.append(INLINE_GREEN)
formattingChar = True
elif fCharacter == "~" and not self.nextCharacterIsNotSpecial: #green.
if self.inlineColorStack:
if self.inlineColorStack[-1] == INLINE_RED:
del self.inlineColorStack[-1]
else:
self.inlineColorStack.append(INLINE_RED)
else:
self.inlineColorStack.append(INLINE_RED)
formattingChar = True
elif fCharacter == "s" and self.nextCharacterIsNotSpecial: # shake
self.setScreenShake(True)
self.nextCharacterIsNotSpecial = False
elif fCharacter == "f" and self.nextCharacterIsNotSpecial: # flash
self.setWhiteFlash(True, 0, 75)
self.nextCharacterIsNotSpecial = False
elif fCharacter == "n" and self.nextCharacterIsNotSpecial: # newline
self.text.insertPlainText("\n")
self.ao2text.insertPlainText("\n")
self.nextCharacterIsNotSpecial = False
else:
self.nextCharacterIsNotSpecial = False
if self.inlineColorStack:
top_color = self.inlineColorStack[-1]
if top_color == INLINE_ORANGE:
html = "<font color=\"" + getTextColor(C_ORANGE).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_BLUE:
html = "<font color=\"" + getTextColor(C_BLUE).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_GREEN:
html = "<font color=\"" + getTextColor(C_GREEN).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_GRAY:
html = "<font color=\"" + getTextColor("_inline_grey").name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_RED:
html = "<font color=\"" + getTextColor(C_RED).name() + "\">" + fCharacter + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
else:
self.text.insertHtml(fCharacter)
self.ao2text.insertHtml(fCharacter)
else:
if int(self.mChatMessage[TEXT_COLOR]) == C_RAINBOW:
self.text.insertHtml(fCharacter)
else:
self.ao2text.insertHtml(fCharacter)
if self.messageIsCentered:
self.ao2text.setAlignment(QtCore.Qt.AlignCenter)
self.text.setAlignment(QtCore.Qt.AlignCenter)
else:
self.ao2text.setAlignment(QtCore.Qt.AlignLeft)
self.text.setAlignment(QtCore.Qt.AlignLeft)
if fMessage[self.tickPos] != " " or self.blankBlip:
if self.blipPos % self.blipRate == 0 and not formattingChar:
self.blipPos = 0
if self.blipsnd:
audio.playhandle(self.blipsnd, 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.realizationsnd, True)
def playObjectionSound(self, charName, objection):
try:
charName = str(charName)
except:
print "WARNING: Can't play objection sound if charName is unicode yet"
if self.objectSound:
if audio.handleisactive(self.objectSound):
audio.stophandle(self.objectSound)
audio.freehandle(self.objectSound)
objecting = ["holdit", "objection", "takethat", "custom"][objection-1]
if objecting:
if exists(AOpath + 'characters/' + charName + '/' + objecting + '.wav'):
self.objectSound = audio.loadhandle(False, AOpath + 'characters/' + charName + '/' + objecting + '.wav', 0, 0, 0)
elif exists(AOpath + 'characters/' + charName + '/' + objecting + '.opus'):
self.objectSound = audio.loadhandle(False, AOpath + 'characters/' + charName + '/' + objecting + '.opus', 0, 0, 0)
else:
self.objectSound = 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.objectSound = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.opus', 0, 0, 0)
else:
self.objectSound = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.wav', 0, 0, 0)
audio.sethandleattr(self.objectSound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0)
audio.playhandle(self.objectSound, 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.soundslider.value() / 100.0)
if self.sound:
audio.playhandle(self.sound, True)
def playMusic(self, mus):
if mus == "~stop.mp3":
self.stopMusic()
return
if not mus.endswith(".mp3") and "===MUSIC START===.mp3" in self.musicList: #vidya workaround
mus += ".mp3"
musl = mus.lower()
#musp = urllib.unquote(urlparse(musl).path)[1:]
self.stopMusic()
if exists(AOpath + 'sounds/music/' + musl):
self.music = audio.loadhandle(False, AOpath + 'sounds/music/' + musl, 0, 0, BASS_SAMPLE_LOOP)
audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0)
audio.playhandle(self.music, True)
if self.musicslider.value() == 0:
audio.pausehandle(self.music)
elif ini.read_ini_bool("AO2XP.ini", "General", "download music", True):
if mus.lower().startswith("http"):
#self.music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP)
self.music = audio.loadURLhandle(mus, 0, BASS_SAMPLE_LOOP)
print "[audio] Trying to play", mus
else:
for bucket in buckets:
if not bucket: continue
print "[audio] Music stream:", bucket+'base/sounds/music/' + mus
self.music = audio.loadURLhandle(bucket+'base/sounds/music/' + musl, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP)
if self.music: break
if self.music:
audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0)
audio.playhandle(self.music, True)
if self.musicslider.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 and midis, because, why not?
musext = os.path.splitext(basename(musl))[-1]
if musext in ['.mid', '.midi']:
self.specialStream = 1
elif musext in ['.xm', '.mod', '.mo3', '.it', '.s3m', '.mtm', '.umx']:
self.specialStream = 2
if (musl.startswith("https") and error == 2) or self.specialStream:
print "[audio] Downloading music with urllib2"
self.downloadThread = MusicDownloadThread(self, mus)
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:
if self.specialStream == 2:
audio.freeMOD(self.music)
self.specialStream = 0
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 == 1:
self.music = audio.loadMIDI(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP)
elif self.specialStream == 2:
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.musicslider.value() / 100.0)
audio.playhandle(self.music, True)
if self.musicslider.value() == 0:
audio.pausehandle(self.music)
def loadAllMusic(self):
for song, fname in self.musicList.items():
songitem = QtGui.QListWidgetItem()
songitem.setText(song)
if exists(unicode(AOpath + 'sounds/music/' + fname.replace("<and>","&").lower())):
songitem.setBackgroundColor(QtGui.QColor(self.found_songitem_color))
#else:
#songitem.setBackgroundColor(QtGui.QColor(255, 128, 128))
self.musicitems.addItem(songitem)
def loadAllEvidence(self, evi):
self.evidence = evi
if self.evidencedropdown.count() > 0:
self.evidencedropdown.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.evidencedropdown.addItem(evi[0].strip())
if not self.evidence:
self.evidencedropdown.setCurrentIndex(0)
self.evidencedesc.setText('.')
else:
self.evidencedropdown.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.player_list.addItem("[%s]" % pid)
if not pid in self.playerList:
self.playerList[pid] = ["", "", "", ""]
if utype == 1: # Remove a player
item = self.player_list.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
if item:
self.player_list.takeItem(self.player_list.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.player_list.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.player_list.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:
self.musicList[QtCore.QString(os.path.splitext(basename(song))[0].decode('utf-8').replace("<and>","&"))] = song.decode('utf-8')
if "base/" in webAO_bucket:
webAO_bucket = webAO_bucket.replace("base/", "")
buckets[0] = 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.pairdropdown.clear()
self.paircheckbox.setChecked(False)
if "cccc_ic_support" in features:
self.shownameedit.show()
self.nointerruptbtn.show()
self.paircheckbox.setDisabled(False)
self.paircheckbox.setText("Enable pairing")
for char in charList:
self.pairdropdown.addItem(char[0])
else:
self.shownameedit.hide()
self.nointerruptbtn.hide()
self.paircheckbox.setDisabled(True)
self.paircheckbox.setText("This server does not support pairing.")
self.deskbtn.setDisabled("deskmod" not in features)
self.flipbutton.setDisabled("flipping" not in features)
self.customobject.setVisible("customobjections" in features)
self.yPairOffset.setVisible("y_offset" in features)
self.ypairoffset_l.setVisible("y_offset" in features)
self.colordropdown.clear()
self.colordropdown.addItems(['White', 'Green', 'Red', 'Orange', 'Blue'])
if "yellowtext" in features:
self.colordropdown.addItems(['Yellow', 'Pink', 'Cyan', 'Gray', 'Rainbow', 'Black'])
self.colordropdown.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.realizationbtn.setPressed(False)
self.customobject.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.evidencedropdown.clear()
for evi in evidence:
self.evidencedropdown.addItem(evi[0].strip())
logstart = '<b>--- Log started on ' + time.ctime() + ' ---</b>'
if self.ooclog.toPlainText():
self.ooclog.append("\n"+logstart)
else:
self.ooclog.append(logstart)
if self.iclog.toPlainText():
self.iclog.append("\n"+logstart)
else:
self.iclog.append(logstart)
self.setBackground(background.lower())
self.setScene(True)
self.chatbox.hide()
for msg in joinOOC:
self.ooclog.append(msg)
if self.areasLen:
for i in range(self.areasLen):
areaitem = QtGui.QListWidgetItem()
self.areaitems.addItem(areaitem)
self.loadAllMusic()
self.updateAreaList()
else:
self.noARUP = True
for pid in playerList:
self.updatePlayerList(pid, 0, 0)
for type in range(len(playerList[pid])):
self.updatePlayerList(pid, 1, type, playerList[pid][type])
self.musicslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100))
self.soundslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100))
self.blipslider.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.enableWidgets()
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_deskMods', 'auth_packet', 'customBlips']
self.musicList = OrderedDict([])
self.charSelect.hide()
self.onPVPacket()
self.setBackground("default")
self.setScene(True)
self.chatbox.hide()
self.musicslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100))
self.soundslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100))
self.blipslider.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.player_list.clear()
self.stopMusic()
self.iclog.clear()
self.ooclog.clear()
self.changechar.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.callmodbtn,
self.oocnameinput, self.ooclogin, self.gametab_evidence,
self.gametab_msgqueue, self.gametab_iniswap, self.gametab_mute,
self.gametab_pair, self.gametab_misc, self.gametab_players,
self.gametab_music, self.emotedropdown, self.posdropdown,
self.flipbutton, self.sfxbutton, self.nointerruptbtn,
self.effectdropdown, self.slidebutton, self.deskbtn,
self.additivebtn, self.areaitems, self.shownameedit,
self.colordropdown, self.defensebar.minusbtn, self.prosecutionbar.minusbtn,
self.defensebar.plusbtn, self.prosecutionbar.plusbtn, self.wtcebtn_1,
self.wtcebtn_2, self.notguiltybtn, self.guiltybtn,
self.realizationbtn, self.shakebtn,
]:
widget.setEnabled(not demo)
self.demoslider.setVisible(demo)
self.icchatinput.setVisible(not demo)
if demo:
self.changechar.setText('Disconnect')
else:
self.changechar.setText('Switch &character')
def updateAreaList(self):
try:
for i in range(self.areasLen):
area_players = self.areas[0][i]
area_status = self.areas[1][i].title()
area_cm = self.areas[2][i].decode('utf-8')
area_locked = self.areas[3][i].title()
area_name = self.areas[4][i].decode('utf-8')
if area_status == "Casing":
self.areaitems.item(i).setText("%s\n%s | %s\n%s users | %s" % (area_name, area_status, area_cm, area_players, area_locked))
else:
self.areaitems.item(i).setText("%s\n%s\n%s users | %s" % (area_name, area_status, area_players, area_locked))
if area_locked == "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:
print "[debug] Couldn't update areas"