import thread, time, os, buttons, urllib, charselect, ini, random from os.path import exists, basename from ConfigParserEdit import ConfigParser from constants import * from pybass_constants import * from PyQt4 import QtGui, QtCore from functools import partial from ctypes import create_string_buffer from urllib2 import Request, urlopen import AOsocket import images DESK_MOD = 1 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 LOOPING_SFX = 24 SCREENSHAKE = 25 FRAME_SCREENSHAKE = 26 FRAME_REALIZATION = 27 FRAME_SFX = 28 ADDITIVE = 29 EFFECTS = 30 BLIPS = 31 INLINE_BLUE = 0 INLINE_GREEN = 1 INLINE_ORANGE = 2 INLINE_GRAY = 3 INLINE_RED = 4 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 SCALING_AUTO = 0 SCALING_PIXEL = 1 SCALING_SMOOTH = 2 DOWNLOAD_BLACKLIST = [] VIEWPORT_W = 256*2 VIEWPORT_H = 192*2 def delay(msec): dieTime = QtCore.QTime.currentTime().addMSecs(msec) while QtCore.QTime.currentTime() < dieTime: QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100) def decode_ao_str(text): return text.replace("", "%").replace("", "#").replace("", "#").replace("", "&").replace("", "$") def encode_ao_str(text): return text.replace("%", "").replace("#", "").replace("&", "").replace("$", "") def get_char_ini(char, section, value, default=""): tempini = ConfigParser() return ini.read_ini(AOpath + 'characters/' + char.lower() + '/char.ini', section, value, default) def get_option(section, value, default=""): tempini = ConfigParser() tempini.read("AO2XP.ini") return ini.read_ini(tempini, section, value, default) 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" 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) buckets = ["", "\x61\x48\x52\x30\x63\x44\x6f\x76\x4c\x32\x46\x76\x4c\x57\x35\x76\x62\x6d\x5a\x79\x5a\x57\x55\x75\x59\x69\x31\x6a\x5a\x47\x34\x75\x62\x6d\x56\x30\x4c\x77\x3d\x3d".decode("\x62\x61\x73\x65\x36\x34")] # troll # bucket 0 ("") is used for server's own bucket def download_thread(link, savepath): global DOWNLOAD_BLACKLIST if link in DOWNLOAD_BLACKLIST: return for bucket in buckets: if not bucket: continue i = buckets.index(bucket) print "download missing: %s" % link fp = urllib.urlopen(bucket+link) if fp.getcode() == 200: if not os.path.exists(savepath[:-1]): os.makedirs(savepath[:-1]) with open(savepath, "wb") as f: f.write(fp.read()) print "successfully downloaded:", link return DOWNLOAD_BLACKLIST.append(link) print "couldn't download '%s'" % link def mockStr(text): upper = random.choice([True, False]) if isinstance(text, QtCore.QString): l = QtCore.QStringList(list(text)) for i in range(len(text)): if text[i] == " ": continue l[i] = l[i].toUpper() if upper else l[i].toLower() upper = not upper return l.join("") else: l = list(text) for i in range(len(text)): if text[i] == " ": continue l[i] = l[i].upper() if upper else l[i].lower() upper = not upper return "".join(l) class 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: 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") 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 p_char = p_char.lower().decode('utf-8') 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() 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 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() class AOMovie(QtGui.QLabel): play_once = True done = QtCore.pyqtSignal() use_pillow = 0 pillow_frames = [] pillow_frame = 0 pillow_speed = 1 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 pillow_modes = {".gif": 0, ".apng": 1, ".webp": 2, ".png": 1} 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 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) 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() 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() 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 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) 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) 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 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) self.evidenceload.setToolTip('Import all evidence from a file') self.evidenceload.clicked.connect(self.onImportEvidence) self.evidencesave = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "disk.png"), "", self.gametab_evidence) self.evidencesave.setToolTip('Export all evidence to a file') self.evidencesave.clicked.connect(self.onExportEvidence) self.evidencemoveprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right.png"), "", self.gametab_evidence) self.evidencemoveprivate.setToolTip('Transfer selected evidence to the private inventory') self.evidencemoveprivate.clicked.connect(self.onTransferEvidence) self.evidencemoveallprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_right2.png"), "", self.gametab_evidence) self.evidencemoveallprivate.setToolTip('Transfer all evidence to the private inventory') self.evidencemoveallprivate.clicked.connect(self.onTransferAllEvidence) self.evidencemoveglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left.png"), "", self.gametab_evidence) self.evidencemoveglobal.setToolTip('Transfer selected evidence to the global inventory') self.evidencemoveglobal.clicked.connect(self.onTransferEvidence) self.evidencemoveallglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "arrow_left2.png"), "", self.gametab_evidence) self.evidencemoveallglobal.setToolTip('Transfer all evidence to the global inventory') self.evidencemoveallglobal.clicked.connect(self.onTransferAllEvidence) self.evidenceswitchprivate = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "world.png"), "", self.gametab_evidence) self.evidenceswitchprivate.setToolTip('Switch to the private inventory') self.evidenceswitchprivate.clicked.connect(self.onSwitchInventory) self.evidenceswitchglobal = QtGui.QPushButton(QtGui.QIcon(AO2XPpath + "icons/" + "briefcase.png"), "", self.gametab_evidence) self.evidenceswitchglobal.setToolTip('Switch to the global inventory') self.evidenceswitchglobal.clicked.connect(self.onSwitchInventory) self.evidencepresent = 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) self.clearQueue = QtGui.QPushButton(self.gametab_msgqueue) self.clearQueue.setText('Clear') self.clearQueue.clicked.connect(self.onClicked_clearQueue) 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) self.playerKick = QtGui.QPushButton(self.gametab_players) self.playerKick.setText('Kick') self.playerKick.clicked.connect(self.onClicked_playerKick) self.playerKick.setDisabled(True) self.playerBan = QtGui.QPushButton(self.gametab_players) self.playerBan.setText('Ban') self.playerBan.clicked.connect(self.onClicked_playerBan) self.playerBan.setDisabled(True) self.unmutedlist = QtGui.QListWidget(self.gametab_mute) self.mutedlist = QtGui.QListWidget(self.gametab_mute) self.mutebtn = QtGui.QPushButton(self.gametab_mute) self.unmutebtn = QtGui.QPushButton(self.gametab_mute) self.notmutedlabel = QtGui.QLabel(self.gametab_mute) self.mutedlabel = QtGui.QLabel(self.gametab_mute) self.notmutedlabel.setText('Not muted') self.mutedlabel.setText('Muted') self.mutebtn.setText('>>') self.unmutebtn.setText('<<') self.mutebtn.clicked.connect(self.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) 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') 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)) self.emotedropdown.setToolTip('Select an emotion for your character') self.colordropdown = QtGui.QComboBox(self) self.colordropdown.currentIndexChanged.connect(self.setChatColor) self.colordropdown.setToolTip('Change the color of your message') self.posdropdown = QtGui.QComboBox(self) self.posdropdown.addItems(["def", "pro", "wit", "hld", "hlp", "jud"]) self.posdropdown.currentIndexChanged.connect(self.setPosition) self.posdropdown.setToolTip('Select your position in the courtroom') self.flipbutton = QtGui.QCheckBox(self) self.flipbutton.stateChanged.connect(self.changeFlipCheck) self.flipbutton.setText('Flip') self.flipbutton.resize(self.flipbutton.sizeHint()) self.flipbutton.setToolTip("Mirror your character horizontally") self.sfxbutton = QtGui.QCheckBox(self) self.sfxbutton.setChecked(True) self.sfxbutton.stateChanged.connect(self.changeSfxCheck) self.sfxbutton.setText('Play pre-animation') 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') self.nointerruptbtn.setToolTip("Show the next message immediately, ignoring animations") # AO 2.8 self.additivebtn = QtGui.QCheckBox(self) self.additivebtn.setChecked(False) self.additivebtn.setText('Additive') self.additivebtn.resize(self.additivebtn.sizeHint()) self.additivebtn.clicked.connect(self.onAdditiveCheck) 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()) self.deskbtn.setToolTip('Show or hide the desk in front of your character') self.effectdropdown = QtGui.QComboBox(self) 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() self.realizationbtn = buttons.AOToggleButton(self, 265 + 164, 192 + 304, "realization") self.realizationbtn.clicked.connect(self.onRealizationButton) 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 self.shakebtn.setToolTip('Show the next message with a shaking effect') self.customobject = buttons.CustomObjection(self, 250 + 516 - 30, 312 + 40) 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 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) 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") self.shownameedit.setToolTip('Set a custom name for your character') self.musicslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.soundslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.blipslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.musicslider.setRange(0, 100) self.soundslider.setRange(0, 100) self.blipslider.setRange(0, 100) self.musicslider.valueChanged.connect(self.changeMusicVolume) self.soundslider.valueChanged.connect(self.changeSoundVolume) self.blipslider.valueChanged.connect(self.changeBlipVolume) self.sliderlabel1 = QtGui.QLabel("Music", self) self.sliderlabel2 = QtGui.QLabel("SFX", self) self.sliderlabel3 = QtGui.QLabel("Blips", self) self.pinglabel = QtGui.QLabel(self) self.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 = '' self.charshowname = '' self.charside = 'def' self.lastmsg = '' self.msgqueue = [] self.selectedmsg = -1 self.evidence = [] self.privateevidence = [] self.selectedevi = -1 self.present = False 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) self.wtcesfx = 0 self.guiltysfx = 0 self.notguiltysfx = 0 self.stream = 0 self.specialstream = 0 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) if value == 0: audio.pausehandle(self.music) elif audio.handleisactive(self.music) == BASS_ACTIVE_PAUSED: audio.playhandle(self.music, False) def changeSoundVolume(self, value): if self.sound: audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, value / 100.0) audio.sethandleattr(self.realizationsnd, BASS_ATTRIB_VOL, value / 100.0) audio.sethandleattr(self.wtcesfx, BASS_ATTRIB_VOL, value / 100.0) audio.sethandleattr(self.guiltysfx, BASS_ATTRIB_VOL, value / 100.0) audio.sethandleattr(self.notguiltysfx, BASS_ATTRIB_VOL, value / 100.0) if self.modcall: audio.sethandleattr(self.modcall, BASS_ATTRIB_VOL, value / 100.0) def changeBlipVolume(self, value): if self.blipsnd: audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, value / 100.0) def setJudgeButtons(self): if self.charside == 'jud': self.defensebar.minusbtn.show() self.defensebar.plusbtn.show() self.prosecutionbar.minusbtn.show() self.prosecutionbar.plusbtn.show() self.wtcebtn_1.show() self.wtcebtn_2.show() self.notguiltybtn.show() self.guiltybtn.show() else: self.defensebar.minusbtn.hide() self.defensebar.plusbtn.hide() self.prosecutionbar.minusbtn.hide() self.prosecutionbar.plusbtn.hide() self.wtcebtn_1.hide() self.wtcebtn_2.hide() self.notguiltybtn.hide() self.guiltybtn.hide() def onChangeShowname(self, text): self.showname = str(text.toUtf8()) 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)) else: guiobj.setPixmap(img) else: img = QtGui.QPixmap(AO2XPpath + 'themes/default/evidence_selected.png') if not img.isNull() and scale: guiobj.setPixmap(img.scaled(140, 140, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.FastTransformation)) else: guiobj.setPixmap(img) if ini.read_ini_bool("AO2XP.ini", "General", "download evidence", True): url = "base/evidence/"+image.lower() url = url.replace("evidence/../", "") path = AOpath+"evidence/"+image path = path.replace("evidence/../", "") thread.start_new_thread(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 self.swapping = False self.iniswapinfo.setText('Not swapped') effectslist = ini.get_effects(charname) self.effectdropdown.setVisible(bool(effectslist)) if effectslist: effectslist.insert(0, "No effect") self.effectdropdown.addItems(effectslist) if isinstance(charname, str): charname = unicode(charname.lower()) elif isinstance(charname, QtCore.QString): charname = unicode(charname.toLower()) #self.charname = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "options", "name", charname.decode('utf-8').lower() self.charname = charname # Just use the folder name self.charshowname = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "options", "showname") if not self.charshowname == "": self.charshowname = self.charshowname.decode('utf-8') self.charside = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "options", "side", "def") self.posdropdown.setCurrentIndex(self.posdropdown.findText(self.charside)) self.setJudgeButtons() for emoteind in range(1, ini.read_ini_int(AOpath+"characters/"+self.charname+"/char.ini", "emotions", "number") + 1): if emoteind == 1: suffix = 'on' else: suffix = 'off' emote = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "emotions", str(emoteind), 'normal#(a)normal#normal#0#') sound = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundn", str(emoteind), '1') soundt = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundt", str(emoteind), '0') soundl = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundl", str(emoteind), '0') # AO 2.8 emotelist = emote.split('#') 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() total_emotes = len(self.charemotes) for button in self.emotebuttons: button.hide() 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: 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') if not image.isNull() and not image.width() == 40: self.emotebuttons[n_emote].setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.FastTransformation)) else: 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: 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 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) 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")) 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") 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]) 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) 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#%') 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 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] 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.') 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.') 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 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: button.path = AOpath + 'characters/' + self.charname + '/emotions/button' + str(button.emoteid + self.current_emote_page * self.max_emotes_on_page + 1) 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: button.setPixmap(image.scaled(40, 40, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.FastTransformation)) else: 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 self.charselect.onDisconnect() self.tcp.close() self.stopMusic() def onMusicClick(self, item): self.sendMC(item.text()) def onAreaClick(self, item): area = item.text().split('\n')[0] self.sendMC(area) def sendMC(self, content): if "cccc_ic_support" in self.features and self.showname: self.tcp.send('MC#' + content + '#' + str(self.mychar) + '#' + self.showname + '#%') else: 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): text = self.oocinput.text().replace('#', '').replace('%', '').replace('&', '').replace('$', '').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(): l = QtCore.QStringList(list(text)) l[0] = l[0].toUpper() last = [".", "?", "!"] if not l[-1] in last: l.append(".") text = l.join("").replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's") if self.spacebartext.isChecked(): l = QtCore.QStringList(list(text)) for i in range(1, len(l)+len(l)-1, 2): l.insert(i, " ") text = l.join("") self.sendOOCchat(self.oocnameinput.text().toUtf8(), text) self.oocinput.clear() def onICreturn(self): text = str(self.icchatinput.text().toUtf8()).replace('#', '').replace('%', '').replace('&', '').replace('$', '').replace('/n', '\n') #if not text: # return if self.mocktext.isChecked(): text = mockStr(text) if self.autocaps.isChecked(): l = list(text) l[0] = l[0].upper() last = [".", "?", "!"] if not l[-1] in last: l.append(".") text = "".join(l).replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's") if self.spacebartext.isChecked(): l = list(text) for i in range(1, len(l)+len(l)-1, 2): l.insert(i, " ") text = "".join(l) emote = self.charemotes[self.selectedemote] if self.nointerruptbtn.isChecked(): modifier = 0 else: modifier = self.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 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: showname = self.showname 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") msg += str(fx + "|" + p_effect + "|" + fx_sound + "#").encode('utf-8') self.effectdropdown.setCurrentIndex(0) msg += "%" 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"], ["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: chatmsgcomp = (self.msgqueue[0].split('#')[5]).replace('', '$').replace('', '%').replace('', '&').replace('', '#') 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(" ") f_char = self.m_chatmessage[CHARNAME].decode("utf-8") evidence = int(self.m_chatmessage[EVIDENCE])-1 t = time.localtime() logcharname = f_char #TODO: UnicodeWarning: Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal #if f_char.lower() != self.charlist[f_char_id][0].lower(): # logcharname = self.charlist[f_char_id][0] + ' (' + f_char.decode("utf-8") + ')' if self.m_chatmessage[SHOWNAME] and self.m_chatmessage[SHOWNAME].lower() != f_char.lower(): try: logcharname += " ("+self.m_chatmessage[SHOWNAME].decode('utf-8')+")" 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]) 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) else: color = QtGui.QColor(255, 255, 255) 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]: self.name.setText(self.m_chatmessage[CHARNAME].decode("utf-8")) else: self.name.setText(self.m_chatmessage[SHOWNAME].decode("utf-8")) 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 = "" if "" 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]) 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 = "" if "" 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()) 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): 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") self.setEvidenceImg(self.presentedevi, f_image, True) self.playSound("sfx-evidenceshoop.opus") if not is_left_side: self.presentedevi.move(170*2, 16*2) else: 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 if exists(AO2XPpath+"callwords.ini"): callwords = [line.rstrip() for line in open(AO2XPpath+"callwords.ini")] for callword in callwords: if callword.decode('utf-8').lower() in self.m_chatmessage[CHATMSG].lower().split(" "): self.ooclog.append("%s called you." % 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 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 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 == " ": self.text.insertPlainText(" ") self.ao2text.insertPlainText(" ") elif f_character == "\n" or f_character == "\r": 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 = "" + f_character + "" 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 = "" + f_character + "" 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 = "" + f_character + "" 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 = "" + f_character + "" 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 = "" + f_character + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_BLUE: html = "" + f_character + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_GREEN: html = "" + f_character + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_GRAY: html = "" + f_character + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) elif top_color == INLINE_RED: html = "" + f_character + "" self.ao2text.insertHtml(html) self.text.insertHtml(html) else: self.text.insertHtml(f_character) self.ao2text.insertHtml(f_character) else: 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) 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) if self.musicslider.value() == 0: audio.pausehandle(self.music) elif ini.read_ini_bool("AO2XP.ini", "General", "download music", True): if mus.lower().startswith("http"): #self.music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP) self.music = audio.loadURLhandle(mus, 0, BASS_SAMPLE_LOOP) print "[audio] Trying to play", mus else: for bucket in buckets: if not bucket: continue print "[audio] Music stream:", bucket+'base/sounds/music/' + mus self.music = audio.loadURLhandle(bucket+'base/sounds/music/' + musl, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP) if self.music: break if self.music: audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) audio.playhandle(self.music, True) if self.musicslider.value() == 0: audio.pausehandle(self.music) else: error = audio.getbasserror() print "[audio] Couldn't play music. Error", error # Here comes the evil HTTPS hack for XP systems, but it also allows us to download and play modules and midis, because, why not? musext = os.path.splitext(basename(musl))[-1] if musext in ['.mid', '.midi']: self.specialstream = 1 elif musext in ['.xm', '.mod', '.mo3', '.it', '.s3m', '.mtm', '.umx']: self.specialstream = 2 if (musl.startswith("https") and error == 2) or self.specialstream: print "[audio] Downloading music with urllib2" self.download_thread = music_download_thread(self, mus) 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) 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 def playDownloadedMusic(self, file_length): # Part of the evil HTTPS music download hack for XP systems print "[audio] Done downloading; trying to play..." if self.specialstream == 1: self.music = audio.loadMIDI(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP) elif self.specialstream == 2: self.music = audio.loadMOD(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP) else: self.music = audio.loadhandle(True, self.stream, 0, file_length, BASS_SAMPLE_LOOP) audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) audio.playhandle(self.music, True) if self.musicslider.value() == 0: audio.pausehandle(self.music) def 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 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) autopick = get_option("General", "auto pick").decode('utf-8').lower() coincidence = -1 for i, char in enumerate(self.charlist): if char[0].lower() == autopick and char[1] == 0: coincidence = i break if coincidence > -1: self.charselect.selectChar(coincidence) else: self.charselect.showCharSelect(False) #putting it down here because some servers won't allow you to switch areas without picking a character first autojoinarea = 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 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 = '--- Log started on ' + time.ctime() + ' ---' if self.ooclog.toPlainText(): self.ooclog.append("\n"+logstart) else: self.ooclog.append(logstart) if self.icLog.toPlainText(): self.icLog.append("\n"+logstart) else: self.icLog.append(logstart) self.setBackground(background.lower()) self.set_scene(True) self.chatbox.hide() for msg in oocjoin: self.ooclog.append(msg) for song in musiclist: song = song.replace("","&").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) for pid in playerlist: self.updatePlayerList(pid, 0, 0) for type in range(len(playerlist[pid])): self.updatePlayerList(pid, 1, type, playerlist[pid][type]) self.musicslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100)) self.soundslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100)) self.blipslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Blip volume", 100)) self.onImportEvidence(True) #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)) self.tcpthread.showCharSelect.connect(self.charselect.showCharSelect) self.tcpthread.allEvidence.connect(self.allEvidence) self.tcpthread.updatePlayerList.connect(self.updatePlayerList) 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) def updatePlayerList(self, pid, op, utype, data=""): pid = str(pid) if op == 0: # Add or remove player 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) if item: self.playerList.takeItem(self.playerList.row(item[0])) if pid in self.playerlist: del self.playerlist[pid] else: # Update a player if pid in self.playerlist: self.playerlist[pid][utype] = data item = self.playerList.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith) if item: name = self.playerlist[pid][0] char = self.playerlist[pid][1] charname = self.playerlist[pid][2] text = "[%s]" % pid if char: text += " %s" % char if charname: text += " (%s)" % charname if name: text += " %s" % name item[0].setText(text) pass 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() 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) 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): 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) 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") 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 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(): 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) 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() def mousePressEvent(self, event): self.gamewindow.current_emote_page -= 1 self.gamewindow.set_emote_page() 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() def mousePressEvent(self, event): self.gamewindow.current_emote_page += 1 self.gamewindow.set_emote_page() 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) rainbowColor = QtCore.pyqtSignal(str) updatePlayerList = QtCore.pyqtSignal(str, int, int, str) send_attempts = 0 max_attempts = 5 def __init__(self, parent): super(TCP_Thread, self).__init__(parent) self.parent = parent def run(self): pingtimer = 150 rainbow = 0 sendtick = 0 tempdata = "" color = QtGui.QColor() 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 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 error, total = self.parent.tcp.recv() if error == -2: # if the message can't be sent, discard it if sendtick == 4: self.send_attempts += 1 if self.send_attempts >= self.max_attempts: self.send_attempts = 0 #print "[warning] message discarded" del self.parent.msgqueue[0] self.parent.msgqueueList.takeItem(0) continue elif error == -1: self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', "%s connection to server lost." % ("WebSocket" if self.parent.tcp.isWS else "TCP")) self.parent.willDisconnect = True self.quit() return else: self.send_attempts = 0 for network in total: header = network[0] #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", "
")) #self.parent.ooclog.append('%s: %s' % (name, chatmsg)) self.OOC_Log.emit("%s: %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('[MOD CALL] ' + network[1].replace("\n", "
") + '
') else: self.OOC_Log.emit('[MOD CALL] But there was no extra information. (old server?)') 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("%s" % (statusStrings[status+1])) elif header == "CHECK": #ping pingafter = time.time() self.parent.gotPing.emit(int((pingafter - pingbefore)*1000)) elif header == 'DONE': self.showCharSelect.emit() elif header == 'PR': del network[0] self.updatePlayerList.emit(network[0], 0, int(network[1]), "") elif header == 'PU': del network[0] self.updatePlayerList.emit(network[0], 1, int(network[1]), network[2].decode('utf-8')) 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: 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: self.parent.areaitems.item(i).setText("%s\n%s\n%s users | %s" % (area_name, area_status, area_players, area_locked)) 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 class music_download_thread(QtCore.QThread): # 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__() 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': '*/*', '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)