diff --git a/AOsocket.py b/AOsocket.py index 939df86..fa0952b 100644 --- a/AOsocket.py +++ b/AOsocket.py @@ -5,7 +5,6 @@ import websocket from constants import * - class AOtcpSocket(object): def __init__(self): self.sock = socket.socket() diff --git a/constants.py b/constants.py index 10b69c3..3f580d3 100644 --- a/constants.py +++ b/constants.py @@ -1,3 +1,72 @@ GAME_VERSION = "2.8.0" AOpath = "base/" -AO2XPpath = "AO2XPbase/" \ No newline at end of file +AO2XPpath = "AO2XPbase/" + +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 +SLIDE = 32 + +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 + +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_scaling(scaling_str): + if scaling_str == "pixel" or scaling_str == "fast": + return SCALING_PIXEL + elif scaling_str == "smooth": + return SCALING_SMOOTH + else: + return SCALING_AUTO diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..dfeb3a2 --- /dev/null +++ b/demo.py @@ -0,0 +1,151 @@ +import ini, packets +from PyQt4 import QtCore +from bisect import bisect_left + +class DemoPlayer(QtCore.QObject): + MS_Chat = QtCore.pyqtSignal(list) + newChar = QtCore.pyqtSignal(str) + newBackground = QtCore.pyqtSignal(str, bool) + IC_Log = QtCore.pyqtSignal(str) + OOC_Log = QtCore.pyqtSignal(str) + charSlots = QtCore.pyqtSignal() + allEvidence = QtCore.pyqtSignal(list) + rainbowColor = QtCore.pyqtSignal(str) + updatePlayerList = QtCore.pyqtSignal(str, int, int, str) + timerUpdate = QtCore.pyqtSignal(int, int, int) + + def __init__(self, parent): + super(DemoPlayer, self).__init__(parent) + self.parent = parent + self.paused = False + self.demo = [] + self.demo_length = len(self.demo) + self.time = 0 + self.demo_length_ms = 0 + self.wait_timer = QtCore.QTimer(self) + self.wait_timer.setSingleShot(True) + self.wait_timer.timeout.connect(self.timer_done) + + self.mc = [] # Music changes + self.bn = [] # Background changes + self.last_music = "" + self.last_bg = "" + + def start(self, file): + self.wait_timer.stop() + + self.time = 0 + self.demo_length_ms = 0 + self.demo = [] + self.mc = [] + self.bn = [] + self.last_music = "" + self.last_bg = "" + self.load_demo(file) + print "[client] Started demo playback (%s commands)" % self.demo_length + + self.parent.demoslider.setMaximum(self.demo_length - 1) + self.OOC_Log.emit("Demo playback started.") + + secs = self.demo_length_ms / 1000 + mins = secs / 60 + hours = mins / 60 + self.OOC_Log.emit("Approximate duration: %02d:%02d:%02d." % (hours, mins % 60, secs % 60)) + + self.OOC_Log.emit("") + self.step() + + def playpause(self): + self.paused = not self.paused + if not self.paused and self.time < self.demo_length: + self.step() + + def step(self, skip_wait=False): + if self.time >= self.demo_length: + self.time = 0 + + packet = self.demo[self.time] + self.parent.demoslider.blockSignals(True) + self.parent.demoslider.setValue(self.time) + self.parent.demoslider.blockSignals(False) + self.time += 1 + + if packet[0] == "wait": + if skip_wait: + self.time += 1 + else: + self.wait_timer.start(int(packet[1])) + return + + packets.handle_packets(self, [packet], False) + if self.time < self.demo_length: + self.wait_timer.start(1) + else: + self.OOC_Log.emit("Demo playback finished.") + + def seek(self, time): + self.parent.inbox_timer.stop() + self.parent.inboxqueue = [] + self.wait_timer.stop() + self.time = time + + mc_times = [t[0] for t in self.mc] + t = bisect_left(mc_times, self.time) - 1 + if t >= 0: + music = self.mc[t][1][1] + if music != self.last_music: + packets.handle_packets(self, [self.mc[t][1]], False) + self.last_music = music + + bn_times = [t[0] for t in self.bn] + t = bisect_left(bn_times, self.time) - 1 + if t >= 0: + bg = self.bn[t][1][1] + if bg != self.last_bg: + packets.handle_packets(self, [self.bn[t][1]], False) + self.last_bg = bg + + self.step(True) + + def load_demo(self, file): + last_line = "" + time = 0 + with open("logs/" + file) as f: + for line in f: + last_line = last_line + line + if last_line.strip()[-1] == "%": + packet = last_line.split("#")[:-1] + self.demo.append(packet) + if packet[0] == "MC": + self.mc.append((time, packet)) + elif packet[0] == "BN": + self.bn.append((time, packet)) + elif packet[0] == "wait": + self.demo_length_ms += int(packet[1]) + last_line = "" + time += 1 + self.demo_length = len(self.demo) + + def timer_done(self): + if self.paused: + return + self.step() + +class DemoRecorder(): + def __init__(self): + self.demofile = None + self.savedemo = False + + def start(self): + self.savedemo = ini.read_ini_bool("AO2XP.ini", "General", "record demos", False) + + if not exists("logs"): + os.mkdir("logs") + + currtime = time.localtime() + self.demofile = "logs/%d%-2d%-2d %.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]) + + def record(self, packet): + if self.savedemo: + with open(self.demofile, "a") as demofile: + demofile.write("#".join(packet[0])+"#%\n") \ No newline at end of file diff --git a/gameview.py b/gameview.py index ec2f5de..7268797 100644 --- a/gameview.py +++ b/gameview.py @@ -3,7 +3,6 @@ from os.path import exists, basename from ConfigParserEdit import ConfigParser from constants import * from collections import OrderedDict -from bisect import bisect_left from pybass_constants import * from PyQt4 import QtGui, QtCore @@ -11,63 +10,7 @@ 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 -SLIDE = 32 - -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 +import AOsocket, images, packets, demo DOWNLOAD_BLACKLIST = [] @@ -82,12 +25,6 @@ def delay(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) @@ -125,21 +62,13 @@ def get_text_color(textcolor): return QtGui.QColor(187, 187, 187) return QtGui.QColor(0, 0, 0) - + def test_path(*args): for path in args: if exists(path): return path return False - -def get_scaling(scaling_str): - if scaling_str == "pixel" or scaling_str == "fast": - return SCALING_PIXEL - elif scaling_str == "smooth": - return SCALING_SMOOTH - else: - return SCALING_AUTO - + 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 @@ -1397,6 +1326,7 @@ class gui(QtGui.QWidget): self.selectedplayer = -1 self.myflip = 0 self.playsfx = 1 + self.demo_recorder = None self.demo_playing = False self.slide_enabled = bool(get_option("General", "slide", False)) @@ -2828,9 +2758,10 @@ class gui(QtGui.QWidget): 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]) + + pair_order = self.m_chatmessage[OTHER_CHARID].split("^") + if "effects" in self.features and len(pair_order) > 1: + pair_order = int(pair_order[1]) else: pair_order = -1 @@ -3352,7 +3283,8 @@ class gui(QtGui.QWidget): if path: self.sound = audio.loadhandle(False, path, 0, 0, 0) audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0) - audio.playhandle(self.sound, True) + if self.sound: + audio.playhandle(self.sound, True) def playMusic(self, mus): if mus == "~stop.mp3": @@ -3496,6 +3428,9 @@ class gui(QtGui.QWidget): item[0].setText(text) def start_pause_timers(self, command, timer_id, timer_ms): + if timer_id > 4: + return + if command == 0: if not self.onscreen_timer.isActive(): self.onscreen_timer.start(self.timer_tick) @@ -3704,7 +3639,7 @@ class gui(QtGui.QWidget): self.tcpthread.timerUpdate.connect(self.start_pause_timers) self.tcpthread.start() - self.demoplayer = DemoPlayer(self) + self.demoplayer = demo.DemoPlayer(self) self.demoplayer.MS_Chat.connect(self.netmsg_ms) self.demoplayer.newChar.connect(self.onPVPacket) self.demoplayer.newBackground.connect(self.setBackground) @@ -3802,335 +3737,12 @@ class TCP_Thread(QtCore.QThread): else: self.send_attempts = 0 - handle_packets(self, total) + packets.handle_packets(self, total) def stop(self): self.stop_now = True - -class DemoPlayer(QtCore.QObject): - MS_Chat = QtCore.pyqtSignal(list) - newChar = QtCore.pyqtSignal(str) - newBackground = QtCore.pyqtSignal(str, bool) - IC_Log = QtCore.pyqtSignal(str) - OOC_Log = QtCore.pyqtSignal(str) - charSlots = QtCore.pyqtSignal() - allEvidence = QtCore.pyqtSignal(list) - rainbowColor = QtCore.pyqtSignal(str) - updatePlayerList = QtCore.pyqtSignal(str, int, int, str) - timerUpdate = QtCore.pyqtSignal(int, int, int) - - def __init__(self, parent): - super(DemoPlayer, self).__init__(parent) - self.parent = parent - self.paused = False - self.demo = [] - self.demo_length = len(self.demo) - self.time = 0 - self.demo_length_ms = 0 - self.wait_timer = QtCore.QTimer(self) - self.wait_timer.setSingleShot(True) - self.wait_timer.timeout.connect(self.timer_done) - - self.mc = [] # Music changes - self.bn = [] # Background changes - self.last_music = "" - self.last_bg = "" - - def start(self, file): - self.wait_timer.stop() - - self.time = 0 - self.demo_length_ms = 0 - self.demo = [] - self.mc = [] - self.bn = [] - self.last_music = "" - self.last_bg = "" - self.load_demo(file) - print "[client] Started demo playback (%s commands)" % self.demo_length - - self.parent.demoslider.setMaximum(self.demo_length - 1) - self.OOC_Log.emit("Demo playback started.") - - secs = self.demo_length_ms / 1000 - mins = secs / 60 - hours = mins / 60 - self.OOC_Log.emit("Approximate duration: %02d:%02d:%02d." % (hours, mins % 60, secs % 60)) - - self.OOC_Log.emit("") - self.step() - - def playpause(self): - self.paused = not self.paused - if not self.paused and self.time < self.demo_length: - self.step() - - def step(self, skip_wait=False): - if self.time >= self.demo_length: - self.time = 0 - - packet = self.demo[self.time] - self.parent.demoslider.blockSignals(True) - self.parent.demoslider.setValue(self.time) - self.parent.demoslider.blockSignals(False) - self.time += 1 - - if packet[0] == "wait": - if skip_wait: - self.time += 1 - else: - self.wait_timer.start(int(packet[1])) - return - - handle_packets(self, [packet]) - if self.time < self.demo_length: - self.wait_timer.start(1) - else: - self.OOC_Log.emit("Demo playback finished.") - - def seek(self, time): - self.parent.inbox_timer.stop() - self.parent.inboxqueue = [] - self.wait_timer.stop() - self.time = time - - mc_times = [t[0] for t in self.mc] - t = bisect_left(mc_times, self.time) - 1 - if t >= 0: - music = self.mc[t][1][1] - if music != self.last_music: - handle_packets(self, [self.mc[t][1]]) - self.last_music = music - - bn_times = [t[0] for t in self.bn] - t = bisect_left(bn_times, self.time) - 1 - if t >= 0: - bg = self.bn[t][1][1] - if bg != self.last_bg: - handle_packets(self, [self.bn[t][1]]) - self.last_bg = bg - - self.step(True) - - def load_demo(self, file): - last_line = "" - time = 0 - with open("logs/" + file) as f: - for line in f: - last_line = last_line + line - if last_line.strip()[-1] == "%": - packet = last_line.split("#")[:-1] - self.demo.append(packet) - if packet[0] == "MC": - self.mc.append((time, packet)) - elif packet[0] == "BN": - self.bn.append((time, packet)) - elif packet[0] == "wait": - self.demo_length_ms += int(packet[1]) - last_line = "" - time += 1 - self.demo_length = len(self.demo) - - def timer_done(self): - if self.paused: - return - self.step() - -def handle_packets(caller, total): - for network in total: - header = network[0] - if header == 'MS': - if len(network) < 15: - print '[warning]', 'malformed/incomplete MS#chat (IC chat) network message was received' - continue - - if isinstance(network[CHATMSG], unicode): - network[CHATMSG] = decode_ao_str(network[CHATMSG]) - else: - network[CHATMSG] = decode_ao_str(network[CHATMSG].decode('utf-8')) - - caller.MS_Chat.emit(network) - - elif header == 'MC': - music = decode_ao_str(network[1]) - charid = int(network[2]) - t = time.localtime() - timestamp = "[%d:%.2d] " % (t[3], t[4]) if not caller.parent.demo_playing else "" - if charid != -1: - try: - name = caller.parent.charlist[charid][0] - except: - name = 'char id %d' % charid - - if len(network) > 3 and network[3]: - name += " ("+network[3].decode("utf-8")+")" - caller.IC_Log.emit(timestamp + '%s changed the music to %s' % (name, music)) - else: - caller.IC_Log.emit(timestamp + 'The music was changed to %s' % music) - caller.parent.playMusic(music) - - elif header == 'BN': - caller.newBackground.emit(network[1].lower(), True) - - elif header == 'CT': - name = decode_ao_str(network[1].decode('utf-8')) - chatmsg = decode_ao_str(network[2].decode('utf-8').replace("\n", "
")) - caller.OOC_Log.emit("%s: %s" % (name, chatmsg)) - - elif header == 'PV': - caller.parent.mychar = int(network[3]) - caller.parent.charselect.hide() - caller.newChar.emit(caller.parent.charlist[caller.parent.mychar][0]) - - elif header == 'LE': - del network[0] - caller.allEvidence.emit([evi.split('&') for evi in network]) - - elif header == 'ZZ': - if caller.parent.modcall: - audio.freehandle(caller.parent.modcall) - caller.parent.modcall = audio.loadhandle(0, "mod_call.wav", 0, 0, 0) - audio.sethandleattr(caller.parent.modcall, BASS_ATTRIB_VOL, caller.parent.soundslider.value() / 100.0) - audio.playhandle(caller.parent.modcall, False) - - if len(network) > 1: - caller.OOC_Log.emit('[MOD CALL] ' + network[1].replace("\n", "
") + '
') - else: - caller.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)): - caller.parent.charlist[i][1] = int(network[i]) - - caller.charSlots.emit() - - elif header == 'RT': - testimony = network[1] - wtcefile = AOpath+"sounds/general/sfx-testimony2" - if caller.parent.wtcesfx: - audio.freehandle(caller.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 - caller.parent.wtcesfx = audio.loadhandle(False, wtcefile+".opus" if exists(wtcefile+".opus") else wtcefile+".wav", 0, 0, 0) - audio.sethandleattr(caller.parent.wtcesfx, BASS_ATTRIB_VOL, caller.parent.soundslider.value() / 100.0) - audio.playhandle(caller.parent.wtcesfx, True) - caller.parent.WTCEsignal.emit(testimony, variant) - - elif header == 'HP': - kind = int(network[1]) - health = int(network[2]) - caller.parent.healthbars.emit(kind, health) - - elif header == 'KK': - reason = network[1] - caller.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] - caller.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] - caller.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: - caller.parent.login = True - caller.parent.playerKick.setDisabled(False) - caller.parent.playerBan.setDisabled(False) - caller.parent.ooclogin.setText("Lo&g out") - elif status == -1: - caller.parent.login = False - caller.parent.playerKick.setDisabled(True) - caller.parent.playerBan.setDisabled(True) - caller.parent.ooclogin.setText("Lo&gin") - caller.OOC_Log.emit("%s" % (statusStrings[status+1])) - - elif header == "CHECK": #ping - pingafter = time.time() - caller.parent.gotPing.emit(int((pingafter - pingbefore)*1000)) - - elif header == 'DONE': - caller.showCharSelect.emit() - - elif header == 'PR': - del network[0] - caller.updatePlayerList.emit(network[0], 0, int(network[1]), "") - - elif header == 'PU': - del network[0] - caller.updatePlayerList.emit(network[0], 1, int(network[1]), network[2].decode('utf-8')) - - elif header == 'ARUP': - del network[0] - kind = int(network[0]) - caller.parent.areas[kind] = [network[i] for i in range(1, len(network))] - - # This is much harder than doing it during the handshake because of the way the music list is implemented - if caller.parent.no_arup: - caller.parent.no_arup = False - caller.parent.areas_len = len(caller.parent.areas[kind]) - print '[client]', 'The server has %d areas' % caller.parent.areas_len - - if caller.parent.areas_len: - for i in range(caller.parent.areas_len): - area_key, area_val = caller.parent.musiclist.items()[0] - caller.parent.areas[4].append(area_val) - - areaitem = QtGui.QListWidgetItem() - caller.parent.areaitems.addItem(areaitem) - - for j in range(len(network)): - if j != kind: - caller.parent.areas[j].append("") - - # Remove the area from the music list - caller.parent.musiclist.popitem(False) - - caller.parent.allMusic() - - for i in range(caller.parent.areas_len): - area_players = caller.parent.areas[0][i] - area_status = caller.parent.areas[1][i].title() - area_cm = caller.parent.areas[2][i].decode('utf-8') - area_locked = caller.parent.areas[3][i].title() - area_name = caller.parent.areas[4][i].decode('utf-8') - if area_status == "Casing": - caller.parent.areaitems.item(i).setText("%s\n%s | %s\n%s users | %s" % (area_name, area_status, area_cm, area_players, area_locked)) - else: - caller.parent.areaitems.item(i).setText("%s\n%s\n%s users | %s" % (area_name, area_status, area_players, area_locked)) - - if area_locked == "Locked": - caller.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "lock.png")) - else: - caller.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "house.png")) - - elif header == 'TI': - del network[0] - timer_id = int(network[0]) - command = int(network[1]) - time_ms = 0 - if len(network) == 3: - time_ms = int(network[2]) - - caller.timerUpdate.emit(command, timer_id, time_ms) - - # For demos - elif header == 'SC': - del network[0] - caller.parent.charlist = [ [char.split('&')[0].decode('utf-8'), 0, "male", True ] for char in network ] class PresentButton(QtGui.QLabel): - def __init__(self, gamegui, parent): super(PresentButton, self).__init__(parent) self.gamegui = gamegui diff --git a/mainmenu.py b/mainmenu.py index 5e441f9..4b0479b 100644 --- a/mainmenu.py +++ b/mainmenu.py @@ -515,6 +515,9 @@ class AOServerInfo(QtCore.QThread): elif header == 'SC': if self.disconnect: continue + + #print "#".join(network)+"#%" + del network[0] gotChars = True charlist = [ [char.split('&')[0].decode('utf-8'), 0, "male", True ] for char in network ] diff --git a/packets.py b/packets.py new file mode 100644 index 0000000..13e2d6a --- /dev/null +++ b/packets.py @@ -0,0 +1,200 @@ +import time +from constants import * +from PyQt4 import QtGui +def handle_packets(caller, total, record=True): + # Record the packet if demos enabled + if record: + #caller.parent.demo_recorder.record(total) + pass + + for network in total: + header = network[0] + if header == 'MS': + if len(network) < 15: + print '[warning]', 'malformed/incomplete MS#chat (IC chat) network message was received' + continue + + if isinstance(network[CHATMSG], unicode): + network[CHATMSG] = decode_ao_str(network[CHATMSG]) + else: + network[CHATMSG] = decode_ao_str(network[CHATMSG].decode('utf-8')) + + caller.MS_Chat.emit(network) + + elif header == 'MC': + music = decode_ao_str(network[1]) + charid = int(network[2]) + t = time.localtime() + timestamp = "[%d:%.2d] " % (t[3], t[4]) if not caller.parent.demo_playing else "" + if charid != -1: + try: + name = caller.parent.charlist[charid][0] + except: + name = 'char id %d' % charid + + if len(network) > 3 and network[3]: + name += " ("+network[3].decode("utf-8")+")" + caller.IC_Log.emit(timestamp + '%s changed the music to %s' % (name, music)) + else: + caller.IC_Log.emit(timestamp + 'The music was changed to %s' % music) + caller.parent.playMusic(music) + + elif header == 'BN': + caller.newBackground.emit(network[1].lower(), True) + + elif header == 'CT': + name = decode_ao_str(network[1].decode('utf-8')) + chatmsg = decode_ao_str(network[2].decode('utf-8').replace("\n", "
")) + caller.OOC_Log.emit("%s: %s" % (name, chatmsg)) + + elif header == 'PV': + caller.parent.mychar = int(network[3]) + caller.parent.charselect.hide() + caller.newChar.emit(caller.parent.charlist[caller.parent.mychar][0]) + + elif header == 'LE': + del network[0] + caller.allEvidence.emit([evi.split('&') for evi in network]) + + elif header == 'ZZ': + if caller.parent.modcall: + audio.freehandle(caller.parent.modcall) + caller.parent.modcall = audio.loadhandle(0, "mod_call.wav", 0, 0, 0) + audio.sethandleattr(caller.parent.modcall, BASS_ATTRIB_VOL, caller.parent.soundslider.value() / 100.0) + audio.playhandle(caller.parent.modcall, False) + + if len(network) > 1: + caller.OOC_Log.emit('[MOD CALL] ' + network[1].replace("\n", "
") + '
') + else: + caller.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)): + caller.parent.charlist[i][1] = int(network[i]) + + caller.charSlots.emit() + + elif header == 'RT': + testimony = network[1] + wtcefile = AOpath+"sounds/general/sfx-testimony2" + if caller.parent.wtcesfx: + audio.freehandle(caller.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 + caller.parent.wtcesfx = audio.loadhandle(False, wtcefile+".opus" if exists(wtcefile+".opus") else wtcefile+".wav", 0, 0, 0) + audio.sethandleattr(caller.parent.wtcesfx, BASS_ATTRIB_VOL, caller.parent.soundslider.value() / 100.0) + audio.playhandle(caller.parent.wtcesfx, True) + caller.parent.WTCEsignal.emit(testimony, variant) + + elif header == 'HP': + kind = int(network[1]) + health = int(network[2]) + caller.parent.healthbars.emit(kind, health) + + elif header == 'KK': + reason = network[1] + caller.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] + caller.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] + caller.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: + caller.parent.login = True + caller.parent.playerKick.setDisabled(False) + caller.parent.playerBan.setDisabled(False) + caller.parent.ooclogin.setText("Lo&g out") + elif status == -1: + caller.parent.login = False + caller.parent.playerKick.setDisabled(True) + caller.parent.playerBan.setDisabled(True) + caller.parent.ooclogin.setText("Lo&gin") + caller.OOC_Log.emit("%s" % (statusStrings[status+1])) + + elif header == "CHECK": #ping + pingafter = time.time() + caller.parent.gotPing.emit(int((pingafter - pingbefore)*1000)) + + elif header == 'DONE': + caller.showCharSelect.emit() + + elif header == 'PR': + del network[0] + caller.updatePlayerList.emit(network[0], 0, int(network[1]), "") + + elif header == 'PU': + del network[0] + caller.updatePlayerList.emit(network[0], 1, int(network[1]), network[2].decode('utf-8')) + + elif header == 'ARUP': + del network[0] + kind = int(network[0]) + caller.parent.areas[kind] = [network[i] for i in range(1, len(network))] + + # This is much harder than doing it during the handshake because of the way the music list is implemented + if caller.parent.no_arup: + caller.parent.no_arup = False + caller.parent.areas_len = len(caller.parent.areas[kind]) + print '[client]', 'The server has %d areas' % caller.parent.areas_len + + if caller.parent.areas_len: + for i in range(caller.parent.areas_len): + area_key, area_val = caller.parent.musiclist.items()[0] + caller.parent.areas[4].append(area_val) + + areaitem = QtGui.QListWidgetItem() + caller.parent.areaitems.addItem(areaitem) + + for j in range(len(network)): + if j != kind: + caller.parent.areas[j].append("") + + # Remove the area from the music list + caller.parent.musiclist.popitem(False) + + caller.parent.allMusic() + + for i in range(caller.parent.areas_len): + area_players = caller.parent.areas[0][i] + area_status = caller.parent.areas[1][i].title() + area_cm = caller.parent.areas[2][i].decode('utf-8') + area_locked = caller.parent.areas[3][i].title() + area_name = caller.parent.areas[4][i].decode('utf-8') + if area_status == "Casing": + caller.parent.areaitems.item(i).setText("%s\n%s | %s\n%s users | %s" % (area_name, area_status, area_cm, area_players, area_locked)) + else: + caller.parent.areaitems.item(i).setText("%s\n%s\n%s users | %s" % (area_name, area_status, area_players, area_locked)) + + if area_locked == "Locked": + caller.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "lock.png")) + else: + caller.parent.areaitems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "house.png")) + + elif header == 'TI': + del network[0] + timer_id = int(network[0]) + command = int(network[1]) + time_ms = 0 + if len(network) == 3: + time_ms = int(network[2]) + + caller.timerUpdate.emit(command, timer_id, time_ms) + + # For demos + elif header == 'SC': + del network[0] + caller.parent.charlist = [ [char.split('&')[0].decode('utf-8'), 0, "male", True ] for char in network ] \ No newline at end of file