AO2XP/gameview.py

3651 lines
152 KiB
Python
Raw Normal View History

2022-03-27 21:01:18 -04:00
import thread, time, os, buttons, urllib, charselect, ini, random
from os.path import exists, basename
from ConfigParserEdit import ConfigParser
from constants import *
2019-04-03 10:57:23 -04:00
from pybass_constants import *
2021-06-20 01:29:40 -04:00
from PyQt4 import QtGui, QtCore
from functools import partial
2025-02-14 13:00:19 -05:00
from ctypes import create_string_buffer
from urllib2 import Request, urlopen
2021-06-20 01:29:40 -04:00
2022-03-27 21:01:18 -04:00
import AOsocket
import images
2021-03-13 18:19:17 -05:00
DESK_MOD = 1
2019-04-03 10:57:23 -04:00
PREANIM = 2
CHARNAME = 3
ANIM = 4
CHATMSG = 5
SIDE = 6
SFX = 7
EMOTE_MOD = 8
CHAR_ID = 9
SFX_DELAY = 10
SHOUT_MOD = 11
EVIDENCE = 12
FLIP = 13
REALIZATION = 14
TEXT_COLOR = 15
SHOWNAME = 16
OTHER_CHARID = 17
OTHER_NAME = 18
OTHER_EMOTE = 19
SELF_OFFSET = 20
OTHER_OFFSET = 21
OTHER_FLIP = 22
NO_INTERRUPT = 23
2020-08-04 08:37:29 -04:00
LOOPING_SFX = 24
SCREENSHAKE = 25
FRAME_SCREENSHAKE = 26
FRAME_REALIZATION = 27
FRAME_SFX = 28
ADDITIVE = 29
EFFECTS = 30
2025-02-17 15:35:41 -05:00
BLIPS = 31
2019-04-03 10:57:23 -04:00
INLINE_BLUE = 0
INLINE_GREEN = 1
INLINE_ORANGE = 2
INLINE_GRAY = 3
2020-08-06 07:09:17 -04:00
INLINE_RED = 4
2019-04-03 10:57:23 -04:00
C_WHITE = 0
C_GREEN = 1
C_RED = 2
C_ORANGE = 3
C_BLUE = 4
C_YELLOW = 5
C_PINK = 6
C_CYAN = 7
C_GRAY = 8
C_RAINBOW = 9
C_BLACK = 10
2019-04-03 10:57:23 -04:00
SCALING_AUTO = 0
SCALING_PIXEL = 1
SCALING_SMOOTH = 2
2019-04-19 22:48:56 -04:00
DOWNLOAD_BLACKLIST = []
VIEWPORT_W = 256*2
VIEWPORT_H = 192*2
2019-04-03 10:57:23 -04:00
def delay(msec):
dieTime = QtCore.QTime.currentTime().addMSecs(msec)
while QtCore.QTime.currentTime() < dieTime:
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
2019-07-29 11:17:14 -04:00
def decode_ao_str(text):
return text.replace("<percent>", "%").replace("<pound>", "#").replace("<num>", "#").replace("<and>", "&").replace("<dollar>", "$")
2021-03-12 13:39:54 -05:00
def encode_ao_str(text):
return text.replace("%", "<percent>").replace("#", "<pound>").replace("&", "<and>").replace("$", "<dollar>")
2019-04-03 10:57:23 -04:00
def get_char_ini(char, section, value, default=""):
tempini = ConfigParser()
2025-02-17 15:35:41 -05:00
return ini.read_ini(AOpath + 'characters/' + char.lower() + '/char.ini', section, value, default)
2020-08-01 22:15:07 -04:00
def get_option(section, value, default=""):
tempini = ConfigParser()
tempini.read("AO2XP.ini")
return ini.read_ini(tempini, section, value, default)
2019-04-03 10:57:23 -04:00
2020-08-04 23:29:43 -04:00
def get_img_suffix(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"
2019-04-03 10:57:23 -04:00
def get_text_color(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: # OH FUCK MOD
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)
2019-04-03 10:57:23 -04:00
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
2019-04-03 10:57:23 -04:00
def download_thread(link, savepath):
global DOWNLOAD_BLACKLIST
if link in DOWNLOAD_BLACKLIST:
return
for bucket in buckets:
2021-03-13 13:33:09 -05:00
if not bucket: continue
i = buckets.index(bucket)
print "download missing: %s" % link
fp = urllib.urlopen(bucket+link)
if fp.getcode() == 200:
2021-03-12 18:42:33 -05:00
if not os.path.exists(savepath[:-1]):
os.makedirs(savepath[:-1])
2021-03-12 18:42:33 -05:00
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
2019-04-03 10:57:23 -04:00
2019-05-24 20:38:02 -04:00
def mockStr(text):
upper = random.choice([True, False])
2025-02-17 18:20:05 -05:00
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)
2019-05-24 20:38:02 -04:00
2019-04-03 10:57:23 -04:00
class ChatLogs(QtGui.QTextEdit):
def __init__(self, parent, logtype, logfile=None):
QtGui.QTextEdit.__init__(self, parent)
self.type = logtype
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("chatlogs"):
os.mkdir("chatlogs")
if self.savelog:
currtime = time.localtime()
if self.combinelog:
if self.type == 0:
self.logfile = logfile
else:
self.logfile = open("chatlogs/%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w")
else:
if self.type == 0:
self.logfile = open("chatlogs/IC_%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w")
else:
self.logfile = open("chatlogs/OOC_%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w")
else:
2020-08-01 22:15:07 -04:00
self.logfile = None
def __del__(self):
if self.savelog:
self.logfile.close()
def append(self, text):
super(ChatLogs, self).append(text)
if self.savelog:
if isinstance(text, str) or isinstance(text, unicode):
if self.combinelog and not "Log started" in text:
if self.type == 0:
self.logfile.write("[IC] "+text.encode("utf-8")+"\n")
else:
self.logfile.write("[OOC] "+text.encode("utf-8")+"\n")
else:
self.logfile.write(text.encode("utf-8")+"\n")
else:
if self.combinelog and not "Log started" in text:
if self.type == 0:
self.logfile.write("[IC] "+text.toUtf8()+"\n")
else:
self.logfile.write("[OOC] "+text.toUtf8()+"\n")
else:
self.logfile.write(text.toUtf8()+"\n")
2019-04-03 10:57:23 -04:00
class AOCharMovie(QtGui.QLabel):
done = QtCore.pyqtSignal()
use_pillow = 0
pillow_frames = []
pillow_frame = 0
pillow_speed = 0
xx = 0 # for restoring from screenshake
yy = 0 # for restoring from screenshake
def __init__(self, parent):
QtGui.QLabel.__init__(self, parent)
self.resize(VIEWPORT_W, VIEWPORT_H)
self.setAlignment(QtCore.Qt.AlignCenter)
self.time_mod = 62
self.play_once = True
self.m_flipped = False
self.scaling = SCALING_AUTO
self.m_movie = QtGui.QMovie()
self.preanim_timer = QtCore.QTimer(self)
self.preanim_timer.setSingleShot(True)
self.pillow_timer = QtCore.QTimer(self)
self.pillow_timer.setSingleShot(True)
self.preanim_timer.timeout.connect(self.timer_done)
self.pillow_timer.timeout.connect(self.pillow_frame_change)
self.m_movie.frameChanged.connect(self.frame_change)
self.prev_gif_path = ""
def move(self, x, y, screenShaking=False):
if not screenShaking:
self.xx = x
self.yy = y
super(AOCharMovie, self).move(x, y)
def set_flipped(self, flip):
self.m_flipped = flip
def test_path(self, paths):
for path in paths:
if exists(path):
return path
return False
def play(self, p_char, p_emote, emote_prefix, scaling = SCALING_AUTO):
if p_emote[0] == "/" or p_emote[0] == "/":
p_emote = p_emote[1:]
elif "../../characters" in p_emote:
a = p_emote.split("/")
p_char = a[3]
emote = a[4]
emote_prefix = ""
p_emote = emote
self.pillow_frames = []
self.pillow_frame = 0
self.scaling = scaling
2025-02-22 18:25:25 -05:00
p_char = p_char.lower()
p_emote = p_emote.lower()
original_path = self.test_path([AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".gif", AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".gif"])
alt_path = AOpath+"characters/"+p_char+"/"+p_emote+".png"
apng_path = self.test_path([AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".apng", AOpath+"characters/"+p_char+"/"+emote_prefix+"/"+p_emote+".apng"])
webp_path = self.test_path([AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".webp", AOpath+"characters/"+p_char+"/"+emote_prefix+"/"+p_emote+".webp"])
placeholder_path = AO2XPpath+"themes/default/placeholder.gif"
gif_path = ""
if apng_path:
gif_path = apng_path
self.use_pillow = 1
else:
if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".apng"
url = url.replace(" ", "%20")
thread.start_new_thread(download_thread, (url, apng_path))
if webp_path:
gif_path = webp_path
self.use_pillow = 2
else:
if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
url = "base/characters/"+p_char.lower()+"/"+p_emote.lower()+".webp"
url = url.replace(" ", "%20")
thread.start_new_thread(download_thread, (url, webp_path))
if original_path:
gif_path = original_path
self.use_pillow = 0
else:
if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".gif"
url = url.replace(" ", "%20")
thread.start_new_thread(download_thread, (url, original_path))
if exists(alt_path):
gif_path = alt_path
self.use_pillow = 0
else:
if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".png"
url = url.replace(" ", "%20")
thread.start_new_thread(download_thread, (url, alt_path))
if exists(placeholder_path):
gif_path = placeholder_path
else:
gif_path = ""
self.use_pillow = 0
if gif_path == placeholder_path or gif_path == "":
gif_path = self.prev_gif_path
else:
self.prev_gif_path = gif_path
if not self.use_pillow:
self.m_movie.stop()
self.m_movie.setFileName(gif_path)
self.m_movie.start()
elif self.use_pillow == 1: # apng
self.pillow_frames = images.load_apng(apng_path)
if len(self.pillow_frames) > 1:
self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed))
self.set_pillow_frame()
elif self.use_pillow == 2: # webp
self.pillow_frames = images.load_webp(webp_path)
if len(self.pillow_frames) > 1:
self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed))
self.set_pillow_frame()
self.show()
def play_pre(self, p_char, p_emote, duration, scaling = SCALING_AUTO):
p_char = p_char.lower()
2025-02-21 00:59:47 -05:00
gif_path = AOpath+"characters/"+p_char+"/"+p_emote+".gif"
apng_path = AOpath+"characters/"+p_char+"/"+p_emote+".apng"
webp_path = AOpath+"characters/"+p_char+"/"+p_emote+".webp"
full_duration = duration * self.time_mod
real_duration = 0
self.play_once = False
self.m_movie.stop()
self.clear()
if exists(apng_path):
real_duration = images.get_apng_duration(apng_path)
elif exists(webp_path):
real_duration = images.get_webp_duration(webp_path)
elif exists(gif_path):
self.m_movie.setFileName(gif_path)
self.m_movie.jumpToFrame(0)
for n_frame in range(self.m_movie.frameCount()):
real_duration += self.m_movie.nextFrameDelay()
self.m_movie.jumpToFrame(n_frame + 1)
percentage_modifier = 100.0
if real_duration != 0 and duration != 0:
modifier = full_duration / float(real_duration)
percentage_modifier = 100 / modifier
if percentage_modifier > 100.0 or percentage_modifier < 0.0:
percentage_modifier = 100.0
self.pillow_fullduration = full_duration
if full_duration == 0 or full_duration >= real_duration:
self.play_once = True
else:
self.play_once = False
if full_duration >= 0:
self.preanim_timer.start(full_duration)
self.m_movie.setSpeed(int(percentage_modifier))
self.pillow_speed = percentage_modifier / 100.
self.play(p_char, p_emote, "", scaling)
def play_talking(self, p_char, p_emote, scaling = SCALING_AUTO):
p_char = p_char.lower()
gif_path = AOpath + 'characters/' + p_char + '/(b)' + p_emote + '.gif'
self.m_movie.stop()
self.clear()
self.m_movie.setFileName(gif_path)
self.m_movie.jumpToFrame(0)
self.play_once = False
self.m_movie.setSpeed(100)
self.pillow_speed = 1
self.play(p_char, p_emote, '(b)', scaling)
def play_idle(self, p_char, p_emote, scaling = SCALING_AUTO):
p_char = p_char.lower()
gif_path = AOpath + 'characters/' + p_char + '/(a)' + p_emote + '.gif'
self.m_movie.stop()
self.clear()
self.m_movie.setFileName(gif_path)
self.m_movie.jumpToFrame(0)
self.play_once = False
self.m_movie.setSpeed(100)
self.pillow_speed = 1
self.play(p_char, p_emote, '(a)', scaling)
def stop(self):
self.m_movie.stop()
self.preanim_timer.stop()
self.hide()
def get_transform(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
@QtCore.pyqtSlot(int)
def frame_change(self, n_frame):
f_img = self.m_movie.currentImage().mirrored(self.m_flipped, False)
if not f_img.isNull():
f_img = f_img.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, self.get_transform(f_img.size().height() > VIEWPORT_H))
f_pixmap = QtGui.QPixmap.fromImage(f_img)
self.setPixmap(f_pixmap)
if self.m_movie.frameCount() - 1 == n_frame and self.play_once:
self.preanim_timer.start(self.m_movie.nextFrameDelay())
@QtCore.pyqtSlot()
def pillow_frame_change(self):
if not self.pillow_frames: return
2025-02-21 00:59:47 -05:00
if len(self.pillow_frames) - 1 == self.pillow_frame:
if self.play_once:
self.preanim_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
elif len(self.pillow_frames) > 1:
self.pillow_frame = 0
self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
else:
self.pillow_frame += 1
self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
self.set_pillow_frame()
def set_pillow_frame(self):
f_img = self.pillow_frames[self.pillow_frame][0].mirrored(self.m_flipped, False)
if not f_img.isNull():
f_img = f_img.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, self.get_transform(f_img.size().height() > VIEWPORT_H))
f_pixmap = QtGui.QPixmap.fromImage(f_img)
self.setPixmap(f_pixmap)
@QtCore.pyqtSlot()
def timer_done(self):
self.done.emit()
2019-04-03 10:57:23 -04:00
class AOMovie(QtGui.QLabel):
play_once = True
done = QtCore.pyqtSignal()
use_pillow = 0
pillow_frames = []
pillow_frame = 0
pillow_speed = 1
2025-02-15 14:12:39 -05:00
pillow_loops = 0
xx = 0 # for restoring from screenshake
yy = 0 # for restoring from screenshake
def __init__(self, parent):
QtGui.QLabel.__init__(self, parent)
self.m_movie = QtGui.QMovie()
self.setMovie(self.m_movie)
self.m_movie.frameChanged.connect(self.frame_change)
self.pillow_timer = QtCore.QTimer(self)
self.pillow_timer.setSingleShot(True)
self.pillow_timer.timeout.connect(self.pillow_frame_change)
self.pillow_label = QtGui.QLabel(self)
self.pillow_label.setGeometry(0, 0, VIEWPORT_W, VIEWPORT_H)
self.pillow_label.hide()
def move(self, x, y):
self.xx = x
self.yy = y
super(AOMovie, self).move(x, y)
def set_play_once(self, once):
self.play_once = once
def play(self, p_image, p_char=""):
gif_path = p_image
2025-02-15 14:12:39 -05:00
pillow_modes = {".gif": 0, ".apng": 1, ".webp": 2, ".png": 1}
2025-02-12 22:31:36 -05:00
p_image = unicode(p_image)
if not exists(gif_path):
pathlist = [
get_img_suffix(AO2XPpath+"themes/default/"+p_image+"_bubble"),
get_img_suffix(AOpath+"characters/"+p_char+"/"+p_image),
get_img_suffix(AOpath+"misc/default/"+p_image),
get_img_suffix(AO2XPpath+"themes/default/"+p_image),
#AO2XPpath+"themes/default/placeholder.gif"
]
for f in pathlist:
if exists(f):
gif_path = f
break
2025-02-15 14:12:39 -05:00
self.use_pillow = pillow_modes[os.path.splitext(gif_path)[1]]
if not self.use_pillow:
self.m_movie.setFileName(gif_path)
self.m_movie.start()
elif self.use_pillow == 1: # apng
self.pillow_label.show()
self.pillow_frames = images.load_apng(gif_path)
if len(self.pillow_frames) > 1:
self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed))
self.set_pillow_frame()
elif self.use_pillow == 2: # webp
self.pillow_label.show()
self.pillow_loops = 0
self.pillow_frames, self.webp_loops = images.load_webp(gif_path)
if len(self.pillow_frames) > 1:
self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed))
self.set_pillow_frame()
self.show()
def stop(self):
self.pillow_frames = []
self.pillow_frame = 0
self.pillow_timer.stop()
self.m_movie.stop()
self.pillow_label.clear()
self.pillow_label.hide()
self.hide()
@QtCore.pyqtSlot(int)
def frame_change(self, n_frame):
if n_frame == self.m_movie.frameCount() - 1 and self.play_once:
delay(self.m_movie.nextFrameDelay())
self.stop()
self.done.emit()
@QtCore.pyqtSlot()
def pillow_frame_change(self):
if not self.pillow_frames: return
if len(self.pillow_frames)-1 == self.pillow_frame:
if self.play_once or (self.use_pillow == 2 and self.pillow_loops+1 == self.webp_loops):
delay(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
self.stop()
self.done.emit()
elif len(self.pillow_frames) > 1: # loop
self.pillow_loops += 1
self.pillow_frame = 0
self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
elif len(self.pillow_frames) > 1:
self.pillow_frame += 1
self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed))
self.set_pillow_frame()
def set_pillow_frame(self):
if not self.pillow_frames: return
f_img = self.pillow_frames[self.pillow_frame][0]
if not f_img.isNull() and (f_img.size().width() != VIEWPORT_W or f_img.size().height() != VIEWPORT_H):
f_img = f_img.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)
f_pixmap = QtGui.QPixmap.fromImage(f_img)
self.pillow_label.setPixmap(f_pixmap)
2020-08-04 23:29:43 -04:00
2019-04-03 10:57:23 -04:00
class ZoomLines(QtGui.QLabel):
def __init__(self, parent):
super(ZoomLines, self).__init__(parent)
self.resize(VIEWPORT_W, VIEWPORT_H)
self.setScaledContents(True)
self.movie = QtGui.QMovie()
self.movie.frameChanged.connect(self.frame_change)
def frame_change(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()
2019-04-03 10:57:23 -04:00
class WTCE_View(QtGui.QLabel):
def __init__(self, parent):
super(WTCE_View, self).__init__(parent)
self.movie = QtGui.QMovie()
self.movie.frameChanged.connect(self.frame_change)
self.finalframe_timer = QtCore.QTimer()
self.finalframe_timer.setSingleShot(False)
self.finalframe_timer.timeout.connect(self.finished)
self.resize(VIEWPORT_W, VIEWPORT_H)
def frame_change(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(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
if self.movie.currentFrameNumber() == self.movie.frameCount() - 1:
self.finalframe_timer.start(self.movie.nextFrameDelay())
def finished(self):
self.finalframe_timer.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()
2019-04-03 10:57:23 -04:00
class gui(QtGui.QWidget):
gamewindow = None
sound = None
music = None
next_character_is_not_special = False
message_is_centered = False
current_display_speed = 3
message_display_speed = (30, 40, 50, 60, 75, 100, 120)
entire_message_is_blue = False
inline_color_stack = [] #"colour" is for EU nobos
inline_blue_depth = 0
other_charid = -1
offset_with_pair = 0
tick_pos = 0
blip_pos = 0
blip_rate = 1
time_mod = 40
blip = "male"
blipsnd = None
2025-02-17 15:35:41 -05:00
chatmessage_size = 32
m_chatmessage = []
blank_blip = False
chatmessage_is_empty = False
is_additive = False
additive_char = -1
anim_state = 3
text_state = 2
objection_state = 0
text_color = 0
charini = ConfigParser()
chatmsg = ''
charid = -1
login = False
privateinv = False
scaling = [SCALING_AUTO, SCALING_AUTO]
#ICchat = QtCore.pyqtSignal(str, str, str, str, str, str, int, int, int, int, int, int, int, int)
#ICchat = QtCore.pyqtSignal(list)
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.chatmessage_size):
self.m_chatmessage.append("")
self.chat_tick_timer = QtCore.QTimer(self)
self.chat_tick_timer.timeout.connect(self.chat_tick)
self.sfx_delay_timer = QtCore.QTimer(self)
self.sfx_delay_timer.setSingleShot(True)
self.sfx_delay_timer.timeout.connect(self.play_sfx)
self.modcall = None
self.healthbars.connect(self.netmsg_hp)
self.disconnectnow = False
self.swapping = False
self.iniswapindex = 0
self.background = 'default'
self.viewport = QtGui.QWidget(self)
self.viewport.resize(VIEWPORT_W, VIEWPORT_H)
self.court = QtGui.QLabel(self.viewport)
self.court.resize(VIEWPORT_W, VIEWPORT_H)
self.zoom = ZoomLines(self.viewport)
self.char = AOCharMovie(self.viewport)
self.char.done.connect(self.preanim_done)
self.sidechar = AOCharMovie(self.viewport)
self.sidechar.hide()
self.bench = QtGui.QLabel(self.viewport)
self.bench.resize(VIEWPORT_W, VIEWPORT_H)
bench = QtGui.QPixmap(AOpath + 'background/default/defensedesk.png')
court = QtGui.QPixmap(AOpath + 'background/default/defenseempty.png')
if not court.isNull():
self.court.setPixmap(court.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
if not bench.isNull():
self.bench.setPixmap(bench.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation))
self.effectview = AOMovie(self.viewport)
2025-02-15 14:12:39 -05:00
self.effectview.resize(VIEWPORT_W, VIEWPORT_H)
self.effectview.setScaledContents(True)
font_db = QtGui.QFontDatabase()
font_db.addApplicationFont(AO2XPpath + 'font/Igiari.ttf')
font_db.addApplicationFont(AO2XPpath + 'font/Ace_Name_Regular.ttf')
name_font = QtGui.QFont("Ace Name")
name_font.setPointSize(12)
ao2text_font = QtGui.QFont("Igiari")
ao2text_font.setPointSize(24)
self.chatbox = QtGui.QLabel(self.viewport)
chatbox = QtGui.QPixmap(AO2XPpath + 'themes/AceAttorney2x/chatbig.png')
#chatbox = QtGui.QPixmap(AO2XPpath + 'themes/default/chatmed.png')
self.chatboxheight = chatbox.size().height()
self.chatbox.setPixmap(chatbox)
self.chatbox.move(0, VIEWPORT_H - self.chatboxheight)
2025-02-18 23:56:02 -05:00
self.text = QtGui.QTextEdit(self.chatbox)
self.text.setFrameStyle(QtGui.QFrame.NoFrame)
self.text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.text.setReadOnly(True)
self.text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
self.text.setFont(ao2text_font)
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.ao2text.setFont(ao2text_font)
self.name = QtGui.QLabel(self.chatbox)
self.name.setFont(name_font)
self.wtceview = WTCE_View(self)
self.WTCEsignal.connect(self.wtceview.showWTCE)
self.objectionview = AOMovie(self.viewport)
self.objectionview.resize(VIEWPORT_W, VIEWPORT_H)
self.objectionview.setScaledContents(True)
self.objectionview.done.connect(self.objection_done)
self.whiteflashlab = QtGui.QLabel(self.viewport)
self.whiteflashlab.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/realizationflash.png'))
self.whiteflashlab.setGeometry(0, 0, VIEWPORT_W, VIEWPORT_H)
self.whiteflashlab.setScaledContents(True)
self.whiteflashlab.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.shakes_remaining = 0
self.ooclog = ChatLogs(self, 1)
self.ooclog.setReadOnly(True)
self.ooclog.textChanged.connect(self.ooclog_update)
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("Login", self)
self.ooclogin.clicked.connect(self.onOOCLoginBtn)
self.musicareatabs = QtGui.QTabWidget(self)
self.musicitems = QtGui.QListWidget()
self.musicitems.itemDoubleClicked.connect(self.onMusicClick)
self.areaitems = QtGui.QListWidget()
self.areaitems.itemDoubleClicked.connect(self.onAreaClick)
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
2025-02-13 15:11:51 -05:00
self.gametab_players = QtGui.QWidget() # client list
self.icLog = ChatLogs(self.gametab_log, 0, self.ooclog.logfile)
self.icLog.setReadOnly(True)
self.icLog.textChanged.connect(self.icLogChanged)
self.evidencedropdown = QtGui.QComboBox(self.gametab_evidence)
self.evidencedropdown.currentIndexChanged.connect(self.changeGlobalEvidence)
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
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)
2025-02-19 21:25:08 -05:00
self.evidenceswitchglobal.setToolTip('Switch to the global inventory')
self.evidenceswitchglobal.clicked.connect(self.onSwitchInventory)
self.evidencepresent = PresentButton(self, self.gametab_evidence)
self.privatedropdown.hide()
self.evidencemoveglobal.hide()
self.evidencemoveallglobal.hide()
self.evidenceswitchglobal.hide()
self.msgqueueList = QtGui.QListWidget(self.gametab_msgqueue)
self.msgqueueList.itemClicked.connect(self.onClicked_msgqueue)
self.removeQueue = QtGui.QPushButton(self.gametab_msgqueue)
self.removeQueue.setText('Delete')
self.removeQueue.clicked.connect(self.onClicked_removeQueue)
2025-02-18 14:42:40 -05:00
self.clearQueue = QtGui.QPushButton(self.gametab_msgqueue)
self.clearQueue.setText('Clear')
self.clearQueue.clicked.connect(self.onClicked_clearQueue)
2025-02-13 15:11:51 -05:00
self.playerList = QtGui.QListWidget(self.gametab_players)
self.playerList.itemClicked.connect(self.onClicked_playerList)
self.playerPair = QtGui.QPushButton(self.gametab_players)
self.playerPair.setText('Pair')
self.playerPair.clicked.connect(self.onClicked_playerPair)
2025-02-13 15:11:51 -05:00
self.playerKick = QtGui.QPushButton(self.gametab_players)
self.playerKick.setText('Kick')
self.playerKick.clicked.connect(self.onClicked_playerKick)
self.playerKick.setDisabled(True)
2025-02-13 15:11:51 -05:00
self.playerBan = QtGui.QPushButton(self.gametab_players)
self.playerBan.setText('Ban')
self.playerBan.clicked.connect(self.onClicked_playerBan)
self.playerBan.setDisabled(True)
2025-02-13 15:11:51 -05:00
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.onMuteClick)
self.unmutebtn.clicked.connect(self.onUnmuteClick)
self.mutedlist.itemClicked.connect(self.changeMuteIndex)
self.unmutedlist.itemClicked.connect(self.changeUnmuteIndex)
self.iniswaplist = QtGui.QComboBox(self.gametab_iniswap)
self.iniswaplist.currentIndexChanged.connect(self.iniswap_index_change)
self.iniswapconfirm = QtGui.QPushButton(self.gametab_iniswap)
self.iniswapconfirm.setText('Swap')
self.iniswapconfirm.clicked.connect(self.iniswap_confirm)
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(mockStr("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)
2025-02-13 15:11:51 -05:00
self.gametabs.addTab(self.gametab_log, 'Log')
self.gametabs.addTab(self.gametab_evidence, 'Evidence')
self.gametabs.addTab(self.gametab_mute, 'Mute')
self.gametabs.addTab(self.gametab_iniswap, 'INI swap')
self.gametabs.addTab(self.gametab_pair, 'Pair')
self.gametabs.addTab(self.gametab_misc, 'Misc')
self.gametabs.addTab(self.gametab_msgqueue, 'Queue')
2025-02-19 15:03:36 -05:00
self.musicareatabs.addTab(self.musicitems, "Music")
self.musicareatabs.addTab(self.areaitems, "Areas")
self.musicareatabs.addTab(self.gametab_players, 'Players')
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))
2025-02-19 21:25:08 -05:00
self.emotedropdown.setToolTip('Select an emotion for your character')
self.colordropdown = QtGui.QComboBox(self)
self.colordropdown.currentIndexChanged.connect(self.setChatColor)
2025-02-19 21:25:08 -05:00
self.colordropdown.setToolTip('Change the color of your message')
self.posdropdown = QtGui.QComboBox(self)
self.posdropdown.addItems(["def", "pro", "wit", "hld", "hlp", "jud"])
self.posdropdown.currentIndexChanged.connect(self.setPosition)
2025-02-19 21:25:08 -05:00
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())
2025-02-19 21:25:08 -05:00
self.flipbutton.setToolTip("Mirror your character horizontally")
self.sfxbutton = QtGui.QCheckBox(self)
self.sfxbutton.setChecked(True)
self.sfxbutton.stateChanged.connect(self.changeSfxCheck)
self.sfxbutton.setText('Play pre-animation')
2025-02-19 21:25:08 -05:00
self.sfxbutton.setToolTip("Play a character-specific animation before the next message")
self.nointerruptbtn = QtGui.QCheckBox(self)
self.nointerruptbtn.setChecked(False)
self.nointerruptbtn.setText('No Interrupt')
2025-02-19 21:25:08 -05:00
self.nointerruptbtn.setToolTip("Show the next message immediately, ignoring animations")
2020-08-04 23:29:43 -04:00
# AO 2.8
self.additivebtn = QtGui.QCheckBox(self)
self.additivebtn.setChecked(False)
2025-02-17 17:00:29 -05:00
self.additivebtn.setText('Additive')
self.additivebtn.resize(self.additivebtn.sizeHint())
self.additivebtn.clicked.connect(self.onAdditiveCheck)
2025-02-19 21:25:08 -05:00
self.additivebtn.setToolTip('Append the next message to the previous one, without a new textbox')
self.deskbtn = QtGui.QCheckBox(self)
self.deskbtn.setChecked(True)
self.deskbtn.setText('Desk')
self.deskbtn.resize(self.nointerruptbtn.sizeHint())
2025-02-19 21:25:08 -05:00
self.deskbtn.setToolTip('Show or hide the desk in front of your character')
self.effectdropdown = QtGui.QComboBox(self)
2025-02-19 21:25:08 -05:00
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.onClick_callMod)
self.settingsbtn = QtGui.QPushButton("Settings", self)
self.settingsbtn.clicked.connect(self.gamewindow.showSettings)
self.changechar = QtGui.QPushButton(self)
self.changechar.setText('Switch character')
self.changechar.clicked.connect(self.onClick_changeChar)
spacing = 1
x_mod_count = y_mod_count = 0
left, top = (10 + 516, 218+190-24)
width, height = (288, 98)
columns = (width - 40) / (spacing + 40) + 1
rows = (height - 40) / (spacing + 40) + 1
self.max_emotes_on_page = columns * rows
self.emotebuttons = []
for i in range(self.max_emotes_on_page):
x_pos = (40 + spacing) * x_mod_count
y_pos = (40 + spacing) * y_mod_count
self.emotebuttons.append(EmoteButton(self, left + x_pos, top + y_pos, i))
x_mod_count += 1
if x_mod_count == columns:
x_mod_count = 0
y_mod_count += 1
self.emotebuttons[i].show()
self.current_emote_page = 0
self.prevemotepage = BackEmoteButton(self, 520, 253+190-28)
self.prevemotepage.hide()
self.nextemotepage = NextEmoteButton(self, 282 + 516, 253+190-28)
self.nextemotepage.show()
2025-02-21 14:34:48 -05:00
self.realizationbtn = buttons.AOToggleButton(self, 265 + 164, 192 + 304, "realization")
self.realizationbtn.clicked.connect(self.onRealizationButton)
2025-02-19 21:25:08 -05:00
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, 265+42 + 164, 192 + 304, "screenshake") # AO 2.8
2025-02-19 21:25:08 -05:00
self.shakebtn.setToolTip('Show the next message with a shaking effect')
self.customobject = buttons.CustomObjection(self, 250 + 516 - 30, 312 + 40)
2025-02-21 14:34:48 -05:00
self.takethatbtn = buttons.Objections(self, 170+ 516 - 20, 312 + 40, 3)
self.objectbtn = buttons.Objections(self, 90+ 516 - 10, 312 + 40, 2)
self.holditbtn = buttons.Objections(self, 10+ 516, 312 + 40, 1)
self.objectsnd = 0
2025-02-21 14:34:48 -05:00
self.defensebar = buttons.PenaltyBars(self, 1)
self.prosecutionbar = buttons.PenaltyBars(self, 2)
self.defensebar.minusClicked.connect(self.penaltyBarMinus)
self.defensebar.plusClicked.connect(self.penaltyBarPlus)
self.prosecutionbar.minusClicked.connect(self.penaltyBarMinus)
self.prosecutionbar.plusClicked.connect(self.penaltyBarPlus)
self.wtcebtn_1 = buttons.WTCEbuttons(self, 429, 544, 0)
self.wtcebtn_2 = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.wtcebtn_1.y() + self.wtcebtn_1.size().height(), 1)
self.notguiltybtn = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.wtcebtn_2.y() + self.wtcebtn_2.size().height(), 2, 0)
self.guiltybtn = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.notguiltybtn.y() + self.notguiltybtn.size().height(), 2, 1)
self.wtcebtn_1.clicked.connect(self.WTCEbuttonPressed)
self.wtcebtn_2.clicked.connect(self.WTCEbuttonPressed)
self.notguiltybtn.clicked.connect(self.WTCEbuttonPressed)
self.guiltybtn.clicked.connect(self.WTCEbuttonPressed)
self.wtcebtn_1.show()
self.wtcebtn_2.show()
self.notguiltybtn.show()
self.guiltybtn.show()
self.presenting = -1
self.presentedevi = QtGui.QLabel(self)
2025-02-12 18:30:18 -05:00
self.presentedevi.setGeometry(16, 16, 140, 140)
self.presentedevi.hide()
self.showname = ""
self.shownameedit = QtGui.QLineEdit(self)
self.shownameedit.textChanged.connect(self.onChangeShowname)
self.shownameedit.setPlaceholderText("Showname")
2025-02-19 21:25:08 -05:00
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)
2025-02-20 13:29:29 -05:00
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.name.show()
self.char.show()
self.court.show()
self.bench.show()
self.chatbox.show()
self.areas = []
self.areas_len = 0
self.muteselected = -1
self.unmuteselected = -1
self.muted = []
self.mychar = -1
self.mychatcolor = 0
self.charemotes = []
self.selectedemote = 0
self.charname = ''
2025-02-17 17:23:18 -05:00
self.charshowname = ''
self.charside = 'def'
2025-02-12 18:30:18 -05:00
self.lastmsg = ''
self.msgqueue = []
self.selectedmsg = -1
self.evidence = []
self.privateevidence = []
self.selectedevi = -1
self.present = False
2025-02-13 15:11:51 -05:00
self.playerlist = {}
self.selectedplayer = -1
self.myflip = 0
self.playsfx = 1
self.loadSwapCharacters()
self.iniswaplist.setCurrentIndex(0)
self.evidence_editor = EditEvidenceDialog(self)
self.connect(self, QtCore.SIGNAL('showMessage(QString, QString, QString)'), self.showMessage)
self.setBackground('default')
self.charselect = charselect.charselect(self)
2025-02-12 22:49:55 -05:00
2025-02-13 01:32:56 -05:00
self.wtcesfx = 0
self.guiltysfx = 0
self.notguiltysfx = 0
2025-02-14 13:00:19 -05:00
self.stream = 0
2025-02-14 17:35:05 -05:00
self.specialstream = 0
2025-02-14 13:00:19 -05:00
self.download_thread = None
# Finally, load the theme
self.width = 820
self.height = 730
theme = get_option("General", "theme", "default")
try:
exec open(AO2XPpath+"ao2xp_themes/"+theme+"/theme.py")
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.shakes_remaining -= 1
shakeforce = 8
if self.shakes_remaining:
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), VIEWPORT_H - self.chatboxheight + random.randint(-shakeforce, shakeforce))
self.ao2text.move(-self.chatbox.x()+16, (VIEWPORT_H-self.chatboxheight-self.chatbox.y())+32)
self.text.move(-self.chatbox.x()+16, (VIEWPORT_H-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, VIEWPORT_H-self.chatboxheight)
self.ao2text.move(16, 32)
self.text.move(16,32)
self.screenshake.stop()
def onAdditiveCheck(self):
if self.additivebtn.isChecked():
self.icchatinput.home(False)
self.icchatinput.insert(" ")
self.icchatinput.end(False)
self.icchatinput.setFocus()
def onRealizationButton(self):
if self.realizationbtn.isPressed():
self.effectdropdown.setCurrentIndex(1) # realization
elif self.effectdropdown.currentText() == "realization":
self.effectdropdown.setCurrentIndex(0)
def onOOCLoginBtn(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()
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)
2025-02-20 12:31:50 -05:00
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)
2025-02-13 01:32:56 -05:00
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 onChangeShowname(self, text):
self.showname = str(text.toUtf8())
2025-02-12 18:30:18 -05:00
def setEvidenceImg(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))
2025-02-12 18:30:18 -05:00
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))
2025-02-12 18:30:18 -05:00
else:
guiobj.setPixmap(img)
2025-02-12 18:30:18 -05:00
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(download_thread, (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 onMuteClick(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 onUnmuteClick(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 penaltyBarMinus(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)
def penaltyBarPlus(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)
def setWhiteFlash(self, on, realizationtype=0, msec=0):
self.whiteflashlab.setVisible(on)
if realizationtype == 1:
self.playRealization(f)
if msec:
self.whiteflash.start(msec)
def setScreenShake(self, on, amount=20):
self.shakes_remaining = amount if on else 1
self.screenshake.start(25)
def WTCEbuttonPressed(self, type, variant):
if type != 2:
self.tcp.send('RT#testimony' + str(type + 1) + '#%')
else:
self.tcp.send("RT#judgeruling#" +str(variant)+ "#%")
def onPVPacket(self, charname):
self.gamewindow.setFixedSize(self.width, self.height)
self.gamewindow.center()
if not self.swapping:
self.loadCharacter(charname)
def loadCharacter(self, charname):
self.msgqueueList.clear()
self.msgqueue = []
self.effectdropdown.clear()
self.emotedropdown.clear()
self.charemotes = []
self.selectedemote = 0
self.current_emote_page = 0
2025-02-12 18:30:18 -05:00
2025-02-17 17:38:40 -05:00
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)
2025-02-12 22:31:36 -05:00
2025-02-17 17:00:29 -05:00
if isinstance(charname, str):
charname = unicode(charname.lower())
elif isinstance(charname, QtCore.QString):
charname = unicode(charname.toLower())
2025-02-12 22:31:36 -05:00
#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
2025-02-17 17:23:18 -05:00
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")
2025-02-12 22:31:36 -05:00
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('#')
del emotelist[len(emotelist) - 1]
emotelist.append(sound)
emotelist.append(soundt)
emotelist.append(soundl) # AO 2.8
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.set_emote_page()
def set_emote_page(self):
if self.mychar < 0:
return
self.prevemotepage.hide()
self.nextemotepage.hide()
2025-02-21 14:34:48 -05:00
total_emotes = len(self.charemotes)
for button in self.emotebuttons:
button.hide()
2025-02-21 14:34:48 -05:00
if not total_emotes:
print "[client] The selected character appears to have no emotions defined"
return
total_pages = total_emotes / self.max_emotes_on_page
emotes_on_page = 0
if total_emotes % self.max_emotes_on_page != 0:
total_pages += 1
if total_pages > self.current_emote_page + 1:
emotes_on_page = self.max_emotes_on_page
else:
emotes_on_page = total_emotes % self.max_emotes_on_page
else:
emotes_on_page = self.max_emotes_on_page
if total_pages > self.current_emote_page + 1:
self.nextemotepage.show()
if self.current_emote_page > 0:
self.prevemotepage.show()
for n_emote in range(emotes_on_page):
n_real_emote = n_emote + self.current_emote_page * self.max_emotes_on_page
if n_real_emote == self.selectedemote:
2025-02-12 22:31:36 -05:00
image = QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(n_real_emote + 1) + '_on.png')
else:
image = QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(n_real_emote + 1) + '_off.png')
2025-02-21 14:34:48 -05:00
if not image.isNull() and not image.width() == 40:
2025-02-12 22:31:36 -05:00
self.emotebuttons[n_emote].setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.FastTransformation))
else:
2025-02-12 22:31:36 -05:00
self.emotebuttons[n_emote].setPixmap(image)
self.emotebuttons[n_emote].show()
self.emotebuttons[n_emote].setToolTip(self.charemotes[n_emote + self.current_emote_page * self.max_emotes_on_page][0])
def iniswap_index_change(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 iniswap_confirm(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.evidence_editor.show()
def onEditEvidence(self):
if not self.evidence:
2025-02-13 16:36:10 -05:00
return QtGui.QMessageBox.information(self, 'No evidence', "There's no evidence on the court record.")
self.evidence_editor.EditEvidence(self.selectedevi)
def onDeleteEvidence(self):
if self.selectedevi == -1:
return
2025-02-18 14:42:40 -05:00
if not self.privateinv:
if self.evidence:
self.tcp.send('DE#' + str(self.selectedevi) + '#%')
else:
self.tcp.send('DE#0#%')
elif len(self.privateevidence):
del self.privateevidence[self.selectedevi]
self.privatedropdown.removeItem(self.selectedevi)
2025-02-20 12:12:26 -05:00
def onExportEvidence(self, is_autosave=False):
if not exists("evidence"):
os.mkdir("evidence")
path = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save evidence", "evidence", "Evidence (*.ini)")) if not is_autosave else "evidence/inventory.ini"
if path:
evidence = self.evidence if not self.privateinv 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'))
inifile.set(id, "description", evi[1].replace('\n', '\\n'))
inifile.set(id, "image", evi[2])
else:
inifile.set(id, "name", evi[0].replace('\n', '\\n').encode('utf-8'))
inifile.set(id, "description", evi[1].replace('\n', '\\n').encode('utf-8'))
inifile.set(id, "image", evi[2].encode('utf-8'))
inifile.write(open(path, "wb"))
2025-02-18 14:42:40 -05:00
2025-02-20 12:12:26 -05:00
def onImportEvidence(self, is_autoload=False):
if not is_autoload:
if not self.privateinv:
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")
2025-02-20 12:12:26 -05:00
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").decode('utf-8').replace('\\n', '\n')
description = ini.read_ini(inifile, section, "description").decode('utf-8').replace('\\n', '\n')
image = ini.read_ini(inifile, section, "image", "empty.png")
evidence.append([name, description, image])
2025-02-20 12:12:26 -05:00
if self.privateinv 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.selectedevi)
2025-02-20 12:12:26 -05:00
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.selectedevi) + '#%')
for evi in evidence:
self.tcp.send('PE#' + evi[0] + '#' + evi[1] + '#' + evi[2] + '#%')
def onTransferEvidence(self):
if self.privateinv:
evi = self.privateevidence[self.selectedevi]
target = self.evidence
target_str = "global"
else:
evi = self.evidence[self.selectedevi]
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.privateinv:
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.privateinv:
evi = self.privateevidence[self.selectedevi]
origin = self.privateevidence
target = self.evidence
target_str = "global"
else:
evi = self.evidence[self.selectedevi]
origin = self.evidence
target = self.privateevidence
target_str = "private"
for evi in origin:
if evi in target:
fail.append(evi[0])
else:
if self.privateinv:
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.privateinv = not self.privateinv
if self.privateinv 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 onClick_callMod(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 onClick_changeChar(self):
#self.tcp.send('RD#%')
2025-02-21 14:34:48 -05:00
self.charselect.showCharSelect()
def changeFlipCheck(self, on):
if on == 2:
on = 1
self.myflip = on
def changeSfxCheck(self, on):
if on == 2:
on = 1
self.playsfx = on
self.nointerruptbtn.setDisabled(not on)
if on == 0:
self.nointerruptbtn.setChecked(False)
def onClicked_msgqueue(self, item):
for i in range(len(self.msgqueueList)):
if self.msgqueueList.item(i) == item:
self.selectedmsg = i
2025-02-13 15:11:51 -05:00
def onClicked_playerList(self, item):
for i in range(len(self.playerList)):
sel = self.playerList.item(i)
if sel == item:
s = sel.text()
self.selectedplayer = s[1:s.indexOf("]")]
def onClicked_removeQueue(self):
if len(self.msgqueueList) == 0:
return QtGui.QMessageBox.information(self, "No messages in queue", 'Enter a message on the game chat to add one.')
if self.selectedmsg == -1:
return QtGui.QMessageBox.information(self, 'No message selected', 'Select a message from the list to remove it.')
self.msgqueueList.takeItem(self.selectedmsg)
del self.msgqueue[self.selectedmsg]
2025-02-18 14:42:40 -05:00
def onClicked_clearQueue(self):
return QtGui.QMessageBox.information(self, "Clear queue", 'Not implemented.')
def onClicked_playerPair(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.')
2025-02-13 15:11:51 -05:00
def onClicked_playerKick(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.')
2025-02-13 15:11:51 -05:00
def onClicked_playerBan(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.privateinv:
if not kind == 1:
return
evi = self.privateevidence
else:
if not kind == 0:
return
evi = self.evidence
2025-02-19 01:23:17 -05:00
self.selectedevi = ind
if len(evi) > 0:
self.evidencedesc.setText(evi[ind][1])
self.setEvidenceImg(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
if not dropdown:
self.selectedemote = ind + self.current_emote_page * self.max_emotes_on_page
else:
self.selectedemote = ind
for button in self.emotebuttons:
if button.emoteid == ind:
2025-02-12 18:30:18 -05:00
button.path = AOpath + 'characters/' + self.charname + '/emotions/button' + str(button.emoteid + self.current_emote_page * self.max_emotes_on_page + 1)
2025-02-12 22:31:36 -05:00
image = QtGui.QPixmap(button.path + '_on.png')
else:
image = QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(button.emoteid + self.current_emote_page * self.max_emotes_on_page + 1) + '_off.png')
if not image.isNull() and image.width() > 40:
2025-02-12 22:31:36 -05:00
button.setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.FastTransformation))
else:
2025-02-12 22:31:36 -05:00
button.setPixmap(image)
def setChatColor(self, ind):
self.mychatcolor = ind
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.playerList.clear()
self.playerKick.setDisabled(True)
self.playerBan.setDisabled(True)
self.ooclogin.setText("Login")
self.login = False
self.privateinv = False
2025-02-21 14:34:48 -05:00
self.charselect.onDisconnect()
self.tcp.close()
self.stopMusic()
def onMusicClick(self, item):
2025-02-21 04:02:16 -05:00
self.sendMC(item.text())
def onAreaClick(self, item):
area = item.text().split('\n')[0]
2025-02-21 04:02:16 -05:00
self.sendMC(area)
def sendMC(self, content):
if "cccc_ic_support" in self.features and self.showname:
2025-02-21 04:02:16 -05:00
self.tcp.send('MC#' + content + '#' + str(self.mychar) + '#' + self.showname + '#%')
else:
2025-02-21 04:02:16 -05:00
self.tcp.send('MC#' + content + '#' + str(self.mychar) + '#%')
def icLogChanged(self):
if self.icLog.verticalScrollBar().value() == self.icLog.verticalScrollBar().maximum(): self.icLog.verticalScrollBar().setValue(self.icLog.verticalScrollBar().maximum())
def ooclog_update(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):
2025-02-17 01:20:52 -05:00
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 = mockStr(text)
if self.autocaps.isChecked():
2025-02-17 18:20:05 -05:00
l = QtCore.QStringList(list(text))
l[0] = l[0].toUpper()
last = [".", "?", "!"]
if not l[-1] in last:
l.append(".")
2025-02-17 18:20:05 -05:00
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 = str(self.icchatinput.text().toUtf8()).replace('#', '<num>').replace('%', '<percent>').replace('&', '<and>').replace('$', '<dollar>').replace('/n', '\n')
2025-02-14 22:02:33 -05:00
#if not text:
# return
if self.mocktext.isChecked():
text = mockStr(text)
if self.autocaps.isChecked():
l = list(text)
l[0] = l[0].upper()
2025-02-17 18:20:05 -05:00
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.playsfx
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 = "MS#"
if "deskmod" in self.features: # visible desk modifier
msg += "%d#" % self.deskbtn.isChecked()
else:
msg += "chat#"
msg += emote[1]+"#" #pre-anim
msg += self.charname.title()+"#"
msg += emote[2]+"#" #anim
2025-02-12 22:31:36 -05:00
msg += text.decode('utf-8')+"#"
msg += self.charside+"#"
msg += 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.selectedevi + 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:
2025-02-22 18:25:25 -05:00
showname = self.showname.decode('utf-8')
2025-02-17 17:23:18 -05:00
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"):
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 ""
fx_sound = ini.get_effect_sound(fx, self.charname)
p_effect = ini.read_ini(AOpath+"characters/"+self.charname+"/char.ini", "options", "effects")
2025-02-12 18:30:18 -05:00
msg += str(fx + "|" + p_effect + "|" + fx_sound + "#").encode('utf-8')
self.effectdropdown.setCurrentIndex(0)
msg += "%"
2025-02-12 18:30:18 -05:00
2025-02-15 12:48:59 -05:00
self.msgqueueList.addItem(self.icchatinput.text())
self.msgqueue.append(msg)
self.lastmsg = msg
self.icchatinput.clear()
self.realizationbtn.setPressed(False)
self.shakebtn.setPressed(False)
def setBackground(self, bg):
if not exists(AOpath + 'background/' + bg):
bg = 'default'
for bgfile in [["side_def", "defenseempty"],
2021-05-26 22:02:16 -04:00
["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() != VIEWPORT_W or bgimg.size().height() != VIEWPORT_H:
setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(VIEWPORT_W, VIEWPORT_H, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)))
else:
setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg))
else:
setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg))
self.set_scene(True)
self.chatbox.hide()
self.char.hide()
def netmsg_hp(self, type, health):
if type == 1:
self.defensebar.setHealth(health)
elif type == 2:
self.prosecutionbar.setHealth(health)
def netmsg_ms(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
for n_string in range(self.chatmessage_size):
if n_string < len(p_contents) and (n_string < 16 or AO2chat):
self.m_chatmessage[n_string] = p_contents[n_string]
else:
self.m_chatmessage[n_string] = ""
f_char_id = int(self.m_chatmessage[CHAR_ID])
if f_char_id < 0 or f_char_id >= len(self.charlist):
return
f_showname = ""
if not self.m_chatmessage[SHOWNAME]:
f_showname = self.m_chatmessage[CHARNAME]
else:
f_showname = self.m_chatmessage[SHOWNAME]
self.text_state = 0
self.anim_state = 0
self.objectionview.stop()
self.char.stop()
self.chat_tick_timer.stop()
self.presentedevi.hide()
self.chatmessage_is_empty = self.m_chatmessage[CHATMSG] == " " or self.m_chatmessage[CHATMSG] == ""
if self.msgqueue:
2025-02-12 22:31:36 -05:00
chatmsgcomp = (self.msgqueue[0].split('#')[5]).replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#')
2025-02-17 01:20:52 -05:00
examine = chatmsgcomp == ">" or chatmsgcomp == "<"
special = not chatmsgcomp or chatmsgcomp.isspace()
if examine or (f_char_id == self.mychar and (special or self.m_chatmessage[CHATMSG] == chatmsgcomp)): # our message showed up
del self.msgqueue[0]
self.msgqueueList.takeItem(0)
if self.additivebtn.isChecked():
self.icchatinput.insert(" ")
2025-02-22 18:25:25 -05:00
self.m_chatmessage[CHARNAME] = self.m_chatmessage[CHARNAME].decode("utf-8")
self.m_chatmessage[SHOWNAME] = self.m_chatmessage[SHOWNAME].decode('utf-8')
f_char = self.m_chatmessage[CHARNAME]
evidence = int(self.m_chatmessage[EVIDENCE])-1
t = time.localtime()
2025-02-13 16:36:10 -05:00
logcharname = f_char
2025-02-12 22:49:55 -05:00
#TODO: UnicodeWarning: Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
2025-02-22 18:25:25 -05:00
if f_char.lower() != self.charlist[f_char_id][0].lower():
logcharname = self.charlist[f_char_id][0] + ' (' + f_char.decode("utf-8") + ')'
2025-02-17 19:09:29 -05:00
if self.m_chatmessage[SHOWNAME] and self.m_chatmessage[SHOWNAME].lower() != f_char.lower():
try:
2025-02-22 18:25:25 -05:00
logcharname += " ("+self.m_chatmessage[SHOWNAME]+")"
except:
logcharname += " (???)"
if evidence == -1:
self.icLog.append('[%d:%.2d] %s: %s' % (t[3], t[4], logcharname, self.m_chatmessage[CHATMSG]))
else:
eviname = '(NULL) %d' % evidence
try:
eviname = self.evidence[evidence][0]
except:
pass
self.icLog.append('[%d:%.2d] %s: %s\n%s presented an evidence: %s' % (t[3], t[4], logcharname, self.m_chatmessage[CHATMSG], f_char, eviname))
self.is_additive = (self.m_chatmessage[ADDITIVE] == "1")
custom_objection = "custom"
try: objection_mod = int(self.m_chatmessage[SHOUT_MOD])
except:
if "4&" in self.m_chatmessage[SHOUT_MOD]: # custom objection name
objection_mod = 4
custom_objection = self.m_chatmessage[SHOUT_MOD].split("4&")[1] # get the name
else: # just in case of mindfuckery
objection_mod = 0
if objection_mod <= 4 and objection_mod >= 1:
objections = ["holdit", "objection", "takethat", "custom_objections/"+custom_objection if custom_objection != "custom" else "custom"]
self.objectionview.play(objections[objection_mod-1], f_char.lower())
self.playObjectionSnd(f_char.lower(), objection_mod)
emote_mod = int(self.m_chatmessage[EMOTE_MOD])
if emote_mod == 0:
self.m_chatmessage[EMOTE_MOD] = 1
else:
self.handle_chatmessage_2()
def set_text_color(self):
textcolor = int(self.m_chatmessage[TEXT_COLOR])
2025-02-18 23:56:02 -05:00
is_rainbow = textcolor == C_RAINBOW
if textcolor == 0:
color = QtGui.QColor(255, 255, 255)
elif textcolor == 1:
color = QtGui.QColor(0, 255, 0)
elif textcolor == 2: #OH FUCK MOD
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)
2025-02-18 23:56:02 -05:00
else:
color = QtGui.QColor(255, 255, 255)
2025-02-18 23:56:02 -05:00
if is_rainbow:
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 set_scene(self, init=False):
if not init:
side = self.m_chatmessage[SIDE]
else:
side = 'wit'
if side == 'def':
self.court.setPixmap(self.side_def)
self.bench.setPixmap(self.bench_def)
self.bench.move(0, VIEWPORT_H - self.bench_def.size().height())
self.presentedevi.move(170, 16)
elif side == 'pro':
self.court.setPixmap(self.side_pro)
self.bench.setPixmap(self.bench_pro)
self.bench.move(VIEWPORT_W - self.bench_pro.size().width(), VIEWPORT_H - self.bench_pro.size().height())
self.presentedevi.move(16, 16)
elif side == 'wit':
self.court.setPixmap(self.side_wit)
self.bench.setPixmap(self.bench_wit)
self.bench.move(0, 0)
self.presentedevi.move(16, 16)
elif side == 'hld':
self.court.setPixmap(self.side_hld)
self.bench.setPixmap(self.bench_hld)
self.presentedevi.move(16, 16)
elif side == 'hlp':
self.court.setPixmap(self.side_hlp)
self.bench.setPixmap(self.bench_hlp)
self.presentedevi.move(170, 16)
elif side == 'jud':
self.court.setPixmap(self.side_jud)
self.bench.setPixmap(self.bench_jud)
self.presentedevi.move(16, 16)
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)
self.presentedevi.move(16, 16)
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)
self.presentedevi.move(16, 16)
deskmod = self.m_chatmessage[DESK_MOD]
if deskmod == "0" or (deskmod != "1" and (side in ("jud", "hld", "hlp"))):
self.bench.hide()
else:
self.bench.show()
def objection_done(self):
self.handle_chatmessage_2()
def handle_chatmessage_2(self):
self.zoom.setZoom(False)
self.char.stop()
self.effectview.stop()
if not self.m_chatmessage[SHOWNAME]:
2025-02-22 18:25:25 -05:00
self.name.setText(self.m_chatmessage[CHARNAME])
else:
2025-02-22 18:25:25 -05:00
self.name.setText(self.m_chatmessage[SHOWNAME])
self.chatbox.hide()
self.set_scene()
self.set_text_color()
f_message = self.m_chatmessage[CHATMSG]
if len(f_message) >= 2:
self.message_is_centered = f_message.startswith("~~")
else:
self.ao2text.setAlignment(QtCore.Qt.AlignLeft)
self.text.setAlignment(QtCore.Qt.AlignLeft)
if self.m_chatmessage[FLIP] == "1":
self.char.set_flipped(True)
else:
self.char.set_flipped(False)
side = self.m_chatmessage[SIDE]
emote_mod = int(self.m_chatmessage[EMOTE_MOD])
# AO 2.8: always offset player
hor_offset = vert_offset = 0
if "y_offset" in self.features: # AO 2.9
keyword = "<and>" if "<and>" in self.m_chatmessage[SELF_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
hor_offset = int(self.m_chatmessage[SELF_OFFSET].split(keyword)[0])
vert_offset = int(self.m_chatmessage[SELF_OFFSET].split(keyword)[1]) if len(self.m_chatmessage[SELF_OFFSET].split(keyword)) > 1 else 0
else:
hor_offset = int(self.m_chatmessage[SELF_OFFSET])
2025-02-14 11:31:54 -05:00
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
self.char.move(VIEWPORT_W * hor_offset / 100, VIEWPORT_H * vert_offset / 100)
# check if paired
if not self.m_chatmessage[OTHER_CHARID]:
self.sidechar.hide()
self.sidechar.move(0,0)
else:
if "effects" in self.features:
got_other_charid = int(self.m_chatmessage[OTHER_CHARID].split("^")[0])
else:
got_other_charid = int(self.m_chatmessage[OTHER_CHARID])
if got_other_charid > -1: # user is paired
self.sidechar.show()
if "effects" in self.features:
pair_order = int(self.m_chatmessage[OTHER_CHARID].split("^")[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.m_chatmessage[OTHER_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous
hor2_offset = int(self.m_chatmessage[OTHER_OFFSET].split(keyword)[0])
vert2_offset = int(self.m_chatmessage[OTHER_OFFSET].split(keyword)[1]) if len(self.m_chatmessage[OTHER_OFFSET].split(keyword)) > 1 else 0
else:
hor2_offset = int(self.m_chatmessage[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(VIEWPORT_W * hor2_offset / 100, VIEWPORT_H * vert2_offset / 100)
self.bench.raise_()
self.chatbox.raise_()
self.effectview.raise_()
self.objectionview.raise_()
self.whiteflashlab.raise_()
self.scaling[1] = self.get_scaling(ini.read_ini(AOpath + 'characters/' + self.m_chatmessage[OTHER_NAME] + '/char.ini', "options", "scaling").lower())
self.sidechar.set_flipped(self.m_chatmessage[OTHER_FLIP] == "1")
self.sidechar.play_idle(self.m_chatmessage[OTHER_NAME], self.m_chatmessage[OTHER_EMOTE], self.scaling[1])
else:
self.sidechar.hide()
self.sidechar.move(0, 0)
self.scaling[0] = self.get_scaling(ini.read_ini(AOpath + 'characters/' + self.m_chatmessage[CHARNAME] + '/char.ini', "options", "scaling").lower())
2025-02-14 11:31:54 -05:00
if (emote_mod == 1 or emote_mod == 2 or emote_mod == 6) and self.m_chatmessage[PREANIM] != "-":
# sfx_delay = int(self.m_chatmessage[SFX_DELAY]) * 60
# if sfx_delay > 0:
# self.sfx_delay_timer.start(sfx_delay)
# else:
# self.play_sfx()
self.play_preanim(False)
elif emote_mod == 0 or emote_mod == 5 or self.m_chatmessage[PREANIM] == "-":
if self.m_chatmessage[NO_INTERRUPT] == "0" or self.m_chatmessage[PREANIM] == "-":
self.handle_chatmessage_3()
else:
self.play_preanim(True)
def get_scaling(self, scaling_str):
if scaling_str == "pixel" or scaling_str == "fast":
return SCALING_PIXEL
elif scaling_str == "smooth":
return SCALING_SMOOTH
else:
return SCALING_AUTO
def play_preanim(self, noninterrupting):
2025-02-21 00:59:47 -05:00
f_char = self.m_chatmessage[CHARNAME].lower()
f_preanim = self.m_chatmessage[PREANIM]
ao2_duration = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "time", "%"+f_preanim, -1)
text_delay = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "textdelay", f_preanim, -1)
sfx_delay = int(self.m_chatmessage[SFX_DELAY]) * 60
preanim_duration = 0
if ao2_duration < 0:
preanim_duration = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "time", f_preanim, -1)
else:
preanim_duration = ao2_duration
anim_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".gif"
apng_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".apng"
webp_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".webp"
if (not exists(anim_to_find) and not exists(apng_to_find) and not exists(webp_to_find)) or preanim_duration < 0:
if noninterrupting:
self.anim_state = 4
else:
self.anim_state = 1
self.preanim_done()
self.char.play_pre(f_char, f_preanim, preanim_duration, self.scaling[0])
if noninterrupting:
self.anim_state = 4
else:
self.anim_state = 1
if sfx_delay > 0:
self.sfx_delay_timer.start(sfx_delay)
else:
self.play_sfx()
if text_delay >= 0:
pass #text delay timer, but not now.
if noninterrupting:
self.handle_chatmessage_3()
def preanim_done(self):
self.anim_state = 1
self.handle_chatmessage_3()
def handle_chatmessage_3(self):
self.start_chat_ticking()
f_evi_id = int(self.m_chatmessage[EVIDENCE])
f_side = self.m_chatmessage[SIDE]
emote_mod = int(self.m_chatmessage[EMOTE_MOD])
if f_evi_id > 0 and f_evi_id <= len(self.evidence):
f_image = self.evidence[f_evi_id-1][2]
is_left_side = not (f_side == "def" or f_side == "hlp" or f_side == "jud" or f_side == "jur")
2025-02-12 18:30:18 -05:00
self.setEvidenceImg(self.presentedevi, f_image, True)
2025-02-13 01:32:56 -05:00
self.playSound("sfx-evidenceshoop.opus")
if not is_left_side:
2025-02-12 18:30:18 -05:00
self.presentedevi.move(170*2, 16*2)
else:
2025-02-12 18:30:18 -05:00
self.presentedevi.move(16*2, 16*2)
self.presentedevi.show()
else:
self.presentedevi.hide()
side = self.m_chatmessage[SIDE]
if emote_mod == 5 or emote_mod == 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_anim_state = 0
text_is_blue = int(self.m_chatmessage[TEXT_COLOR]) == 4
if not text_is_blue and self.text_state == 1:
f_anim_state = 2
self.entire_message_is_blue = False
else:
f_anim_state = 3
self.entire_message_is_blue = True
if f_anim_state <= self.anim_state:
return
self.char.stop()
f_char = self.m_chatmessage[CHARNAME]
f_emote = self.m_chatmessage[ANIM]
if f_anim_state == 2:
self.char.play_talking(f_char, f_emote, self.scaling[0])
self.anim_state = 2
else:
self.char.play_idle(f_char, f_emote, self.scaling[0])
self.anim_state = 3
2025-02-20 22:57:42 -05:00
if exists(AO2XPpath+"callwords.ini"):
callwords = [line.rstrip() for line in open(AO2XPpath+"callwords.ini")]
for callword in callwords:
2025-02-20 22:57:42 -05:00
if callword.decode('utf-8').lower() in self.m_chatmessage[CHATMSG].lower().split(" "):
self.ooclog.append("<b>%s called you.</b>" % f_char)
snd = audio.loadhandle(False, "word_call.wav", 0, 0, BASS_STREAM_AUTOFREE)
if snd:
audio.playhandle(snd, True)
break
def do_effect(self, fx_name, fx_sound, p_char, p_folder):
effect = ini.get_effect(fx_name, p_char, p_folder)
if not effect: return
if fx_sound:
self.playSound(fx_sound)
if "effects" not in self.features: return
2025-02-15 14:12:39 -05:00
self.effectview.set_play_once(True)
self.effectview.play(effect)
def start_chat_ticking(self):
if self.text_state != 0:
return
if self.m_chatmessage[EFFECTS]:
fx_list = self.m_chatmessage[EFFECTS].split("|")
fx = fx_list[0]
fx_sound = ""
fx_folder = ""
if len(fx_list) > 1:
fx_sound = fx_list[1]
if len(fx_list) > 2:
fx_folder = fx_list[1]
fx_sound = fx_list[2]
if fx and fx not in ("-", "None"):
self.do_effect(fx, fx_sound, self.m_chatmessage[CHARNAME], fx_folder)
elif self.m_chatmessage[REALIZATION] == "1":
self.setWhiteFlash(True, 1, 125)
self.set_text_color()
charid = int(self.m_chatmessage[CHAR_ID])
if not self.is_additive or self.additive_char != charid:
self.ao2text.clear()
self.text.setText("")
self.additive_char = charid
if self.chatmessage_is_empty:
self.text_state = 2
return
self.inline_color_stack = []
self.chatbox.show()
self.tick_pos = 0
self.blip_pos = 0
self.inline_blue_depth = 0
self.current_display_speed = 3
self.chat_tick_timer.start(self.message_display_speed[self.current_display_speed])
self.blip = self.charlist[charid][2]
if exists(AOpath+"sounds/general/sfx-blip"+self.blip+".wav"):
self.blipsnd = audio.loadhandle(False, AOpath+"sounds/general/sfx-blip"+self.blip+".wav", 0, 0, 0)
elif exists(AOpath+"sounds/general/sfx-blip"+self.blip+".opus"):
self.blipsnd = audio.loadhandle(False, AOpath+"sounds/general/sfx-blip"+self.blip+".opus", 0, 0, 0)
elif exists(AOpath+"sounds/blips/"+self.blip+".wav"):
self.blipsnd = audio.loadhandle(False, AOpath+"sounds/blips/"+self.blip+".wav", 0, 0, 0)
elif exists(AOpath+"sounds/blips/"+self.blip+".opus"):
self.blipsnd = audio.loadhandle(False, AOpath+"sounds/blips/"+self.blip+".opus", 0, 0, 0)
else:
self.blipsnd = 0
2025-02-17 15:35:41 -05:00
if self.blipsnd:
audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, self.blipslider.value() / 100.0)
emote_mod = int(self.m_chatmessage[EMOTE_MOD])
if emote_mod in (0, 5) and self.m_chatmessage[SCREENSHAKE] == "1":
self.setScreenShake(True)
self.text_state = 1
def chat_tick(self):
f_message = self.m_chatmessage[CHATMSG]
self.chat_tick_timer.stop()
formatting_char = False
if self.message_is_centered:
f_message = f_message.strip("~~")
if self.tick_pos >= len(f_message):
self.text_state = 2
if self.anim_state != 4:
self.anim_state = 3
self.char.play_idle(self.m_chatmessage[CHARNAME], self.m_chatmessage[ANIM], self.scaling[0])
else:
f_character2 = f_message[self.tick_pos]
f_character = QtCore.QString(f_character2)
if f_character == " ":
2025-02-18 23:56:02 -05:00
self.text.insertPlainText(" ")
self.ao2text.insertPlainText(" ")
elif f_character == "\n" or f_character == "\r":
2025-02-18 23:56:02 -05:00
self.text.insertPlainText("\n")
self.ao2text.insertPlainText("\n")
elif f_character == "\\" and not self.next_character_is_not_special:
self.next_character_is_not_special = True
formatting_char = True
elif f_character == "{" and not self.next_character_is_not_special:
self.current_display_speed += 1
formatting_char = True
elif f_character == "}" and not self.next_character_is_not_special:
self.current_display_speed -= 1
formatting_char = True
elif f_character == "|" and not self.next_character_is_not_special: #orange.
if self.inline_color_stack:
if self.inline_color_stack[-1] == INLINE_ORANGE:
del self.inline_color_stack[-1]
else:
self.inline_color_stack.append(INLINE_ORANGE)
else:
self.inline_color_stack.append(INLINE_ORANGE)
formatting_char = True
elif f_character == "(" and not self.next_character_is_not_special: #blue.
self.inline_color_stack.append(INLINE_BLUE)
html = "<font color=\"" + get_text_color(4).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
self.inline_blue_depth += 1
if not self.entire_message_is_blue and self.anim_state != 4:
f_char = self.m_chatmessage[CHARNAME]
f_emote = self.m_chatmessage[ANIM]
self.char.play_idle(f_char, f_emote, self.scaling[0])
elif f_character == ")" and not self.next_character_is_not_special and self.inline_color_stack:
if self.inline_color_stack[-1] == INLINE_BLUE:
del self.inline_color_stack[-1]
html = "<font color=\"" + get_text_color(4).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
if self.inline_blue_depth > 0:
self.inline_blue_depth -= 1
if not self.entire_message_is_blue:
if self.inline_blue_depth == 0 and self.anim_state != 4 and not (self.tick_pos+1 >= len(f_message)):
f_char = self.m_chatmessage[CHARNAME]
f_emote = self.m_chatmessage[ANIM]
self.char.play_talking(f_char, f_emote, self.scaling[0])
else:
self.next_character_is_not_special = True
self.tick_pos -= 1
elif f_character == "[" and not self.next_character_is_not_special: #gray.
self.inline_color_stack.append(INLINE_GRAY)
html = "<font color=\"" + get_text_color("_inline_grey").name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif f_character == "]" and not self.next_character_is_not_special and self.inline_color_stack:
if self.inline_color_stack[-1] == INLINE_GRAY:
del self.inline_color_stack[-1]
html = "<font color=\"" + get_text_color("_inline_grey").name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
else:
self.next_character_is_not_special = True
self.tick_pos -= 1
elif f_character == "`" and not self.next_character_is_not_special: #green.
if self.inline_color_stack:
if self.inline_color_stack[-1] == INLINE_GREEN:
del self.inline_color_stack[-1]
else:
self.inline_color_stack.append(INLINE_GREEN)
else:
self.inline_color_stack.append(INLINE_GREEN)
formatting_char = True
elif f_character == "~" and not self.next_character_is_not_special: #green.
if self.inline_color_stack:
if self.inline_color_stack[-1] == INLINE_RED:
del self.inline_color_stack[-1]
else:
self.inline_color_stack.append(INLINE_RED)
else:
self.inline_color_stack.append(INLINE_RED)
formatting_char = True
elif f_character == "s" and self.next_character_is_not_special: # shake
self.setScreenShake(True)
self.next_character_is_not_special = False
elif f_character == "f" and self.next_character_is_not_special: # flash
self.setWhiteFlash(True, 0, 75)
self.next_character_is_not_special = False
elif f_character == "n" and self.next_character_is_not_special: # newline
self.text.insertPlainText("\n")
self.ao2text.insertPlainText("\n")
self.next_character_is_not_special = False
else:
self.next_character_is_not_special = False
if self.inline_color_stack:
top_color = self.inline_color_stack[-1]
if top_color == INLINE_ORANGE:
html = "<font color=\"" + get_text_color(C_ORANGE).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_BLUE:
html = "<font color=\"" + get_text_color(C_BLUE).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_GREEN:
html = "<font color=\"" + get_text_color(C_GREEN).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_GRAY:
html = "<font color=\"" + get_text_color("_inline_grey").name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
elif top_color == INLINE_RED:
html = "<font color=\"" + get_text_color(C_RED).name() + "\">" + f_character + "</font>"
self.ao2text.insertHtml(html)
self.text.insertHtml(html)
else:
self.text.insertHtml(f_character)
self.ao2text.insertHtml(f_character)
else:
2025-02-18 23:56:02 -05:00
if int(self.m_chatmessage[TEXT_COLOR]) == C_RAINBOW:
self.text.insertHtml(f_character)
else:
self.ao2text.insertHtml(f_character)
if self.message_is_centered:
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 f_message[self.tick_pos] != " " or self.blank_blip:
if self.blip_pos % self.blip_rate == 0 and not formatting_char:
self.blip_pos = 0
audio.playhandle(self.blipsnd, True)
self.blip_pos += 1
self.tick_pos += 1
if self.current_display_speed < 0:
self.current_display_speed = 0
elif self.current_display_speed > 6:
self.current_display_speed = 6
if formatting_char:
self.chat_tick_timer.start(1)
else:
self.chat_tick_timer.start(self.message_display_speed[self.current_display_speed])
def playRealization(self):
audio.playhandle(self.realizationsnd, True)
def playObjectionSnd(self, charname, objection):
try:
charname = str(charname)
except:
print "WARNING: Can't play objection sound if charname is unicode yet"
if self.objectsnd:
if audio.handleisactive(self.objectsnd):
audio.stophandle(self.objectsnd)
audio.freehandle(self.objectsnd)
objecting = ["holdit", "objection", "takethat", "custom"][objection-1]
if objecting:
if exists(AOpath + 'characters/' + charname + '/' + objecting + '.wav'):
self.objectsnd = audio.loadhandle(False, AOpath + 'characters/' + charname + '/' + objecting + '.wav', 0, 0, 0)
elif exists(AOpath + 'characters/' + charname + '/' + objecting + '.opus'):
self.objectsnd = audio.loadhandle(False, AOpath + 'characters/' + charname + '/' + objecting + '.opus', 0, 0, 0)
else:
self.objectsnd = None
if ini.read_ini_bool("AO2XP.ini", "General", "download sounds", True):
thread.start_new_thread(download_thread, ("base/characters/"+charname+"/"+objecting+".wav", AOpath+"characters/"+charname+"/"+objecting.lower()+".wav"))
thread.start_new_thread(download_thread, ("base/characters/"+charname+"/"+objecting+".opus", AOpath+"characters/"+charname+"/"+objecting.lower()+".wav"))
if exists(AOpath + 'sounds/general/sfx-objection.opus'):
self.objectsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.opus', 0, 0, 0)
else:
self.objectsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.wav', 0, 0, 0)
audio.sethandleattr(self.objectsnd, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0)
audio.playhandle(self.objectsnd, True)
def play_sfx(self):
sfx_name = self.m_chatmessage[SFX]
if sfx_name == "1" or sfx_name == "0":
return
self.playSound(sfx_name)
def playSound(self, sfx):
if self.sound:
if audio.handleisactive(self.sound):
audio.stophandle(self.sound)
audio.freehandle(self.sound)
2025-02-12 18:30:18 -05:00
if exists(AOpath + 'sounds/general/' + sfx):
self.sound = audio.loadhandle(False, AOpath + 'sounds/general/' + sfx, 0, 0, 0)
audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0)
audio.playhandle(self.sound, True)
elif exists(AOpath + 'sounds/general/' + sfx + '.wav'):
self.sound = audio.loadhandle(False, AOpath + 'sounds/general/' + sfx + '.wav', 0, 0, 0)
audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0)
audio.playhandle(self.sound, True)
elif exists(AOpath + 'sounds/general/' + sfx + '.opus'):
self.sound = audio.loadhandle(False, AOpath + 'sounds/general/' + sfx + '.opus', 0, 0, 0)
audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0)
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()
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)
2025-02-20 12:31:50 -05:00
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"):
2025-02-14 13:00:19 -05:00
#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)
2025-02-20 12:31:50 -05:00
if self.musicslider.value() == 0:
audio.pausehandle(self.music)
else:
2025-02-17 19:09:29 -05:00
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?
2025-02-14 17:35:05 -05:00
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
2025-02-17 19:09:29 -05:00
if (musl.startswith("https") and error == 2) or self.specialstream:
print "[audio] Downloading music with urllib2"
self.download_thread = music_download_thread(self, mus)
2025-02-14 13:00:19 -05:00
self.download_thread.finished_signal.connect(self.playDownloadedMusic)
self.download_thread.start()
def stopMusic(self):
if self.music:
if audio.handleisactive(self.music):
audio.stophandle(self.music)
2025-02-14 17:35:05 -05:00
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.download_thread:
self.download_thread.terminate() # Live dangerously
self.download_thread = None
2025-02-14 13:00:19 -05:00
def playDownloadedMusic(self, file_length):
# Part of the evil HTTPS music download hack for XP systems
print "[audio] Done downloading; trying to play..."
2025-02-14 17:35:05 -05:00
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)
2025-02-14 13:00:19 -05:00
audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0)
2025-02-20 12:31:50 -05:00
audio.playhandle(self.music, True)
if self.musicslider.value() == 0:
audio.pausehandle(self.music)
2025-02-13 15:11:51 -05:00
def startGame(self, tcp, playerlist, charlist, musiclist, background, evidence, areas, features=[], oocjoin=[], hplist=[], webAO_bucket=""):
self.willDisconnect = False
self.mychar = -1
self.mychatcolor = 0
self.tcp = tcp
2025-02-13 15:11:51 -05:00
self.playerlist = playerlist
self.charlist = charlist
self.musiclist = musiclist
self.evidence = evidence
self.areas = areas
self.areas_len = len(areas[0])
self.features = features
if "base/" in webAO_bucket:
webAO_bucket = webAO_bucket.replace("base/", "")
buckets[0] = webAO_bucket
self.charselect.setCharList(charlist)
2025-02-19 23:11:51 -05:00
autopick = get_option("General", "auto pick").decode('utf-8').lower()
2025-02-19 22:30:56 -05:00
coincidence = -1
for i, char in enumerate(self.charlist):
if char[0].lower() == autopick and char[1] == 0:
coincidence = i
break
2025-02-19 22:30:56 -05:00
if coincidence > -1:
self.charselect.selectChar(coincidence)
2025-02-19 22:30:56 -05:00
else:
2025-02-21 14:34:48 -05:00
self.charselect.showCharSelect(False)
2025-02-21 04:02:16 -05:00
#putting it down here because some servers won't allow you to switch areas without picking a character first
autojoinarea = get_option("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.setVisible("flipping" 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
2025-02-17 15:35:41 -05:00
char[2] = get_char_ini(char[0], "Options", "gender").lower()
if char[2] == "":
char[2] = get_char_ini(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])
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)
2025-02-17 17:00:29 -05:00
self.setBackground(background.lower())
self.set_scene(True)
self.chatbox.hide()
for msg in oocjoin:
self.ooclog.append(msg)
for song in musiclist:
song = song.replace("<and>","&").decode('utf-8')
songitem = QtGui.QListWidgetItem()
songitem.setText(song)
if exists(AOpath + 'sounds/music/' + song.lower()):
songitem.setBackgroundColor(QtGui.QColor(128, 255, 128))
#else:
#songitem.setBackgroundColor(QtGui.QColor(255, 128, 128))
self.musicitems.addItem(songitem)
for area in areas[0]:
areaitem = QtGui.QListWidgetItem()
self.areaitems.addItem(areaitem)
2025-02-13 15:11:51 -05:00
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))
2025-02-20 12:12:26 -05:00
self.onImportEvidence(True)
#thread.start_new_thread(self.tcp_thread, ())
self.tcpthread = TCP_Thread(self)
self.tcpthread.MS_Chat.connect(self.netmsg_ms)
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))
2025-02-21 14:34:48 -05:00
self.tcpthread.showCharSelect.connect(self.charselect.showCharSelect)
self.tcpthread.allEvidence.connect(self.allEvidence)
2025-02-13 15:11:51 -05:00
self.tcpthread.updatePlayerList.connect(self.updatePlayerList)
2025-02-18 23:56:02 -05:00
self.tcpthread.rainbowColor.connect(self.text.setStyleSheet)
self.tcpthread.start()
def allEvidence(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] = decode_ao_str(evi[0].decode('utf-8'))
evi[1] = decode_ao_str(evi[1].decode('utf-8'))
evi[2] = decode_ao_str(evi[2].decode('utf-8'))
self.evidencedropdown.addItem(evi[0])
if not self.evidence:
self.evidencedropdown.setCurrentIndex(0)
self.evidencedesc.setText('.')
else:
self.evidencedropdown.setCurrentIndex(self.selectedevi)
2025-02-13 15:11:51 -05:00
2025-02-13 16:36:10 -05:00
def updatePlayerList(self, pid, op, utype, data=""):
pid = str(pid)
2025-02-13 15:11:51 -05:00
if op == 0: # Add or remove player
2025-02-13 16:36:10 -05:00
if utype == 0: # Add a player
self.playerList.addItem("[%s]" % pid)
if not pid in self.playerlist:
self.playerlist[pid] = ["", "", "", ""]
if utype == 1: # Remove a player
item = self.playerList.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
2025-02-13 15:11:51 -05:00
if item:
self.playerList.takeItem(self.playerList.row(item[0]))
2025-02-13 16:36:10 -05:00
if pid in self.playerlist:
del self.playerlist[pid]
2025-02-13 15:11:51 -05:00
else: # Update a player
2025-02-13 16:36:10 -05:00
if pid in self.playerlist:
self.playerlist[pid][utype] = data
2025-02-13 15:11:51 -05:00
2025-02-13 16:36:10 -05:00
item = self.playerList.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
2025-02-13 15:11:51 -05:00
if item:
2025-02-13 16:36:10 -05:00
name = self.playerlist[pid][0]
char = self.playerlist[pid][1]
charname = self.playerlist[pid][2]
text = "[%s]" % pid
2025-02-13 15:11:51 -05:00
if char:
text += " %s" % char
if charname:
text += " (%s)" % charname
if name:
text += " %s" % name
item[0].setText(text)
pass
2019-04-03 10:57:23 -04:00
class PresentButton(QtGui.QLabel):
def __init__(self, gamegui, parent):
super(PresentButton, self).__init__(parent)
self.gamegui = gamegui
self.button_off = QtGui.QPixmap(AO2XPpath + 'themes/default/present_disabled.png')
self.button_on = QtGui.QPixmap(AO2XPpath + 'themes/default/present.png')
self.setPixmap(self.button_off)
self.show()
2019-04-03 10:57:23 -04:00
def mousePressEvent(self, event):
self.gamegui.present = not self.gamegui.present
if self.gamegui.present:
self.setPixmap(self.button_on)
else:
self.setPixmap(self.button_off)
2019-04-03 10:57:23 -04:00
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.onSave)
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.onCancel)
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.onBrowse)
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 onSave(self):
2025-02-17 01:20:52 -05:00
name = encode_ao_str(self.eviname.text())
desc = encode_ao_str(self.evidesc.toPlainText())
if not self.gamegui.privateinv:
if self.editing:
self.gamegui.tcp.send('EE#' + str(self.edit_ind) + '#' + name + '#' + desc + '#' + self.filename + '#%')
else:
self.gamegui.tcp.send('PE#' + name + '#' + desc + '#' + self.filename + '#%')
else:
if self.editing:
self.gamegui.privateevidence[self.gamegui.selectedevi] = [unicode(name), unicode(desc), unicode(self.filename)]
self.gamegui.privatedropdown.setItemText(self.gamegui.selectedevi, name)
evi = self.gamegui.privateevidence[self.gamegui.selectedevi]
self.gamegui.evidencedesc.setText(evi[1])
self.gamegui.setEvidenceImg(self.gamegui.evidenceimage, evi[2])
else:
self.gamegui.privateevidence.append([name, desc, self.filename])
self.gamegui.privatedropdown.addItem(name)
2025-02-20 12:12:26 -05:00
self.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 onCancel(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 onBrowse(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.onBrowse()
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.onBrowse()
def EditEvidence(self, ind):
self.editing = True
self.edit_ind = ind
evidence = self.gamegui.privateevidence if self.gamegui.privateinv 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.privateinv else "Edit evidence in private inventory")
self.show()
def setTitle(self):
self.setWindowTitle('Add evidence' if not self.gamegui.privateinv else "Add evidence to private inventory")
2019-04-03 10:57:23 -04:00
class EmoteButton(QtGui.QLabel):
def __init__(self, gamewindow, x, y, id):
super(EmoteButton, self).__init__(gamewindow)
self.gamewindow = gamewindow
self.resize(40, 40)
self.move(x, y)
self.emoteid = id
2025-02-12 18:30:18 -05:00
self.path = ''
def paintEvent(self, event):
if self.gamewindow.mychar == -1:
return
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.TextAntialiasing, False)
painter.setPen(QtGui.QColor(255, 255, 255))
font = QtGui.QFont("Tahoma", 8)
font.setStyle(QtGui.QFont.StyleNormal)
font.setWeight(QtGui.QFont.Normal)
painter.setFont(font)
if self.pixmap():
if self.pixmap().isNull():
2025-02-12 18:30:18 -05:00
button_img = QtGui.QPixmap(self.path + '_off.png')
painter.setOpacity(0.5)
painter.drawPixmap(0, 0, button_img)
else:
painter.drawPixmap(0, 0, self.pixmap())
else:
painter.fillRect(0, 0, 39, 39, QtGui.QColor(0, 0, 0))
painter.drawText(1, 1, str(self.emoteid))
def mousePressEvent(self, event):
self.gamewindow.changeEmote(False, self.emoteid)
2019-04-03 10:57:23 -04:00
class BackEmoteButton(QtGui.QLabel):
def __init__(self, gamewindow, x, y):
super(BackEmoteButton, self).__init__(gamewindow)
self.gamewindow = gamewindow
self.move(x, y)
self.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/arrow_left.png'))
self.show()
2019-04-03 10:57:23 -04:00
def mousePressEvent(self, event):
self.gamewindow.current_emote_page -= 1
self.gamewindow.set_emote_page()
2019-04-03 10:57:23 -04:00
class NextEmoteButton(QtGui.QLabel):
def __init__(self, gamewindow, x, y):
super(NextEmoteButton, self).__init__(gamewindow)
self.gamewindow = gamewindow
self.move(x, y)
self.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/arrow_right.png'))
self.show()
2019-04-03 10:57:23 -04:00
def mousePressEvent(self, event):
self.gamewindow.current_emote_page += 1
self.gamewindow.set_emote_page()
2019-04-03 10:57:23 -04:00
class TCP_Thread(QtCore.QThread):
connectionError = QtCore.pyqtSignal(str, str, str)
MS_Chat = QtCore.pyqtSignal(list)
newChar = QtCore.pyqtSignal(str)
newBackground = QtCore.pyqtSignal(str)
IC_Log = QtCore.pyqtSignal(str)
OOC_Log = QtCore.pyqtSignal(str)
charSlots = QtCore.pyqtSignal()
showCharSelect = QtCore.pyqtSignal()
allEvidence = QtCore.pyqtSignal(list)
2025-02-18 23:56:02 -05:00
rainbowColor = QtCore.pyqtSignal(str)
2025-02-13 15:11:51 -05:00
updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
2020-08-01 22:15:07 -04:00
2025-02-17 01:20:52 -05:00
send_attempts = 0
max_attempts = 5
def __init__(self, parent):
super(TCP_Thread, self).__init__(parent)
self.parent = parent
def run(self):
pingtimer = 150
2025-02-18 23:56:02 -05:00
rainbow = 0
sendtick = 0
tempdata = ""
color = QtGui.QColor()
2025-02-18 23:56:02 -05:00
color.setHsv(rainbow, 255, 255)
#color.setHsv(0, 255, 255)
while True:
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
2025-02-18 23:56:02 -05:00
if self.parent.m_chatmessage[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.msgqueue and not sendtick:
self.parent.tcp.send(self.parent.msgqueue[0])
sendtick = 4
2022-03-27 21:01:18 -04:00
error, total = self.parent.tcp.recv()
if error == -2:
2025-02-15 12:48:59 -05:00
# if the message can't be sent, discard it
if sendtick == 4:
2025-02-17 01:20:52 -05:00
self.send_attempts += 1
if self.send_attempts >= self.max_attempts:
self.send_attempts = 0
#print "[warning] message discarded"
2025-02-17 01:20:52 -05:00
del self.parent.msgqueue[0]
self.parent.msgqueueList.takeItem(0)
2022-03-27 21:01:18 -04:00
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()
2025-02-17 01:20:52 -05:00
return
else:
self.send_attempts = 0
2022-03-27 21:01:18 -04:00
for network in total:
header = network[0]
2022-03-27 21:01:18 -04:00
#del network[-1]
if header == 'MS':
if len(network) < 15:
print '[warning]', 'malformed/incomplete MS#chat (IC chat) network message was received'
continue
network[CHATMSG] = decode_ao_str(network[CHATMSG].decode('utf-8'))
self.MS_Chat.emit(network)
elif header == 'MC':
music = decode_ao_str(network[1])
charid = int(network[2])
t = time.localtime()
if charid != -1:
try:
name = self.parent.charlist[charid][0]
except:
name = 'char id %d' % charid
if len(network) > 3 and network[3]:
name += " ("+network[3].decode("utf-8")+")"
self.IC_Log.emit('[%d:%.2d] %s changed the music to %s' % (t[3], t[4], name, music))
else:
self.IC_Log.emit('[%d:%.2d] The music was changed to %s' % (t[3], t[4], music))
self.parent.playMusic(music)
elif header == 'BN':
self.newBackground.emit(network[1].lower())
elif header == 'CT':
name = decode_ao_str(network[1].decode('utf-8'))
chatmsg = decode_ao_str(network[2].decode('utf-8').replace("\n", "<br />"))
#self.parent.ooclog.append('<b>%s:</b> %s' % (name, chatmsg))
self.OOC_Log.emit("<b>%s:</b> %s" % (name, chatmsg))
elif header == 'PV':
self.parent.mychar = int(network[3])
self.parent.charselect.hide()
self.newChar.emit(self.parent.charlist[self.parent.mychar][0])
elif header == 'LE':
del network[0]
self.allEvidence.emit([evi.split('&') for evi in network])
elif header == 'ZZ':
if self.parent.modcall:
audio.freehandle(self.parent.modcall)
self.parent.modcall = audio.loadhandle(0, "mod_call.wav", 0, 0, 0)
audio.sethandleattr(self.parent.modcall, BASS_ATTRIB_VOL, self.parent.soundslider.value() / 100.0)
audio.playhandle(self.parent.modcall, False)
if len(network) > 1:
self.OOC_Log.emit('<b>[MOD CALL] ' + network[1].replace("\n", "<br />") + '</b>')
else:
self.OOC_Log.emit('<b>[MOD CALL] But there was no extra information. (old server?)</b>')
elif header == 'CharsCheck':
del network[0]
for i in range(len(network)):
self.parent.charlist[i][1] = int(network[i])
self.charSlots.emit()
elif header == 'RT':
testimony = network[1]
wtcefile = AOpath+"sounds/general/sfx-testimony2"
if self.parent.wtcesfx:
audio.freehandle(self.parent.wtcesfx)
if testimony == 'judgeruling':
variant = int(network[2])
if variant == 0:
wtcefile = AOpath+"sounds/general/sfx-notguilty"
elif variant == 1:
wtcefile = AOpath+"sounds/general/sfx-guilty"
else:
variant = 0
self.parent.wtcesfx = audio.loadhandle(False, wtcefile+".opus" if exists(wtcefile+".opus") else wtcefile+".wav", 0, 0, 0)
audio.sethandleattr(self.parent.wtcesfx, BASS_ATTRIB_VOL, self.parent.soundslider.value() / 100.0)
audio.playhandle(self.parent.wtcesfx, True)
self.parent.WTCEsignal.emit(testimony, variant)
elif header == 'HP':
type = int(network[1])
health = int(network[2])
self.parent.healthbars.emit(type, health)
elif header == 'KK':
reason = network[1]
self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', 'You were kicked from the server. (%s)' % reason)
elif header == 'KB':
reason = network[1]
self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', 'You have been banned from the server. (%s)' % reason)
elif header == 'BB': # message popup (AO 2.9)
message = network[1]
self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'information', 'Message from server', message)
elif header == 'AUTH': # login status (AO 2.9)
status = int(network[1])
statusStrings = ["You have logged out", "Wrong password", "Logged in"]
if status == 1:
self.parent.login = True
self.parent.playerKick.setDisabled(False)
self.parent.playerBan.setDisabled(False)
self.parent.ooclogin.setText("Log out")
elif status == -1:
self.parent.login = False
self.parent.playerKick.setDisabled(True)
self.parent.playerBan.setDisabled(True)
self.parent.ooclogin.setText("Login")
self.OOC_Log.emit("<b>%s</b>" % (statusStrings[status+1]))
2025-02-13 15:11:51 -05:00
elif header == "CHECK": #ping
pingafter = time.time()
self.parent.gotPing.emit(int((pingafter - pingbefore)*1000))
elif header == 'DONE':
self.showCharSelect.emit()
2025-02-13 15:11:51 -05:00
elif header == 'PR':
del network[0]
self.updatePlayerList.emit(network[0], 0, int(network[1]), "")
elif header == 'PU':
del network[0]
2025-02-13 16:36:10 -05:00
self.updatePlayerList.emit(network[0], 1, int(network[1]), network[2].decode('utf-8'))
2025-02-19 01:23:17 -05:00
elif header == 'ARUP':
del network[0]
type = int(network[0])
self.parent.areas[type] = [network[i] for i in range(1, len(network))]
for i in range(self.parent.areas_len):
try:
2025-02-22 17:57:29 -05:00
area_players = self.parent.areas[0][i]
area_status = self.parent.areas[1][i].title()
area_cm = self.parent.areas[2][i].decode('utf-8')
area_locked = self.parent.areas[3][i].title()
area_name = self.parent.areas[4][i].decode('utf-8')
if area_status == "Casing":
self.parent.areaitems.item(i).setText("%s\n%s | %s\n%s users | %s" % (area_name, area_status, area_cm, area_players, area_locked))
else:
2025-02-22 17:57:29 -05:00
self.parent.areaitems.item(i).setText("%s\n%s\n%s users | %s" % (area_name, area_status, area_players, area_locked))
2025-02-22 17:57:29 -05:00
if area_locked == "Locked":
self.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "lock.png"))
else:
self.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "house.png"))
except:
pass
2025-02-14 13:00:19 -05:00
class music_download_thread(QtCore.QThread):
2025-02-14 13:00:19 -05:00
# Part of the evil HTTPS music download hack for XP systems
finished_signal = QtCore.pyqtSignal(int)
def __init__(self, caller, url):
super(music_download_thread, self).__init__()
2025-02-14 13:00:19 -05:00
self.caller = caller
self.url = url
def run(self):
self.download(self.url)
def download(self, url):
headers = {
'User-Agent': "AO2XP %s" % (GAME_VERSION),
'Accept': '*/*',
2025-02-14 13:00:19 -05:00
'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'
response = urlopen(request)
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:
chunk = response.read(buffer_size)
if not chunk:
break
stream += chunk
bytes_downloaded += len(chunk)
self.caller.stream = create_string_buffer(stream)
self.finished_signal.emit(file_length)