diff --git a/AO2XP.py b/AO2XP.py index 89daae6..a6af82a 100644 --- a/AO2XP.py +++ b/AO2XP.py @@ -131,7 +131,7 @@ QtCore.qInstallMsgHandler(handler) audio.init() game = gamewindow() game.show() -app.aboutToQuit.connect(game.gamewidget.disconnectCommon) +app.aboutToQuit.connect(game.gamewidget.exitCommon) returnc = app.exec_() audio.free() sys.exit(returnc) diff --git a/AOsocket.py b/AOsocket.py index ed83fc1..6165100 100644 --- a/AOsocket.py +++ b/AOsocket.py @@ -3,7 +3,6 @@ import platform import websocket import ssl -from PyQt4.QtCore import QString from constants import * @@ -51,10 +50,11 @@ class AOtcpSocket(object): totals[i] = totals[i].split("#") del totals[i][-1] if printPackets: - try: - print "[packet] <-", totals[0] - except: - print "(unable to print)" + for packet in totals: + try: + print "[packet] <-", packet + except: + print "(unable to print)" return 0, totals def send(self, data): @@ -63,14 +63,15 @@ class AOtcpSocket(object): print "[packet] ->", data except: print "(unable to print)" - # Qt pls - if isinstance(data, QString): + if isinstance(data, str) or isinstance(data, unicode): + return self.sock.send(data.encode('utf-8')) + else: + # Probably Qstring #return self.sock.send(unicode(data).encode('utf-8')) return self.sock.send(str(data.toUtf8())) - else: - return self.sock.send(data.encode('utf-8')) def close(self): + print "[debug] TCP connection closed" self.sock.close() class AOwebSocket(object): @@ -118,10 +119,11 @@ class AOwebSocket(object): del totals[i][-1] if printPackets: - try: - print "[packet] <-", totals[0] - except: - print "(unable to print)" + for packet in totals: + try: + print "[packet] <-", packet + except: + print "(unable to print)" return 0, totals def send(self, data): @@ -133,4 +135,5 @@ class AOwebSocket(object): return self.sock.send(unicode(data)) def close(self): + print "[debug] Websocket connection closed" self.sock.close() diff --git a/gameview.py b/gameview.py index 8ac6ea0..458885d 100644 --- a/gameview.py +++ b/gameview.py @@ -109,8 +109,8 @@ def mockString(text): upper = not upper return "".join(l) +# Evil HTTPS music download hack for XP systems class XPMusicDownloadThread(QtCore.QThread): - # Part of the evil HTTPS music download hack for XP systems finishedSignal = QtCore.pyqtSignal(int, str) def __init__(self, caller, url): @@ -1766,6 +1766,13 @@ class GUI(QtGui.QWidget): self.XPDownloadThread = None self.tcp = None self.demoPlayer = None + + # TTS fun + self.speaker = None + if getOption("General", "tts", False) == 'True': + import tts + self.speaker = tts.SpeechThread() + self.speaker.start() # Finally, load the theme self.width = 820 @@ -3026,6 +3033,12 @@ class GUI(QtGui.QWidget): if self.willDisconnect: self.disconnectCommon() self.gamewindow.returnToMenu() + + def exitCommon(self): + self.disconnectCommon() + if self.speaker: + self.speaker.stop() + self.speaker.wait() def disconnectCommon(self): self.onSwitchInventory(True) @@ -3210,10 +3223,11 @@ class GUI(QtGui.QWidget): msg += str(self.myChatColor) + "#" if "cccc_ic_support" in self.features: - showname = self.showname.decode('utf-8') if self.showname == "" and not self.charShowname == "": showname = self.charShowname - msg += showname + "#" # custom showname + else: + showname = self.showname + msg += encodeAOString(showname).decode('utf-8') + "#" # custom showname if self.cbPair.isChecked(): msg += str(self.boxPair.currentIndex()) # pair charID if "effects" in self.features: @@ -3239,10 +3253,10 @@ class GUI(QtGui.QWidget): for f_effect in effects_to_check: packet = "" - for f_emote in emotes_to_check: - packet += f_emote + for fEmote in emotes_to_check: + packet += fEmote if ini.read_ini_bool("AO2XP.ini", "General", "network frame effects", True): - sfx_frames = "|".join(ini.read_ini_tags(AOpath + "characters/"+self.charName+"/char.ini", f_emote + f_effect)) + sfx_frames = "|".join(ini.read_ini_tags(AOpath + "characters/"+self.charName+"/char.ini", fEmote + f_effect)) if sfx_frames: packet += "|" + sfx_frames packet += "^" @@ -3594,6 +3608,10 @@ class GUI(QtGui.QWidget): emoteMod = int(self.mChatMessage[EMOTE_MOD]) if emoteMod == 0: self.mChatMessage[EMOTE_MOD] = 1 + + # TTS fun + if self.speaker: + self.speaker.interrupt.emit() else: # Old behavior #self.mChatMessage = mChatMessage @@ -3755,7 +3773,7 @@ class GUI(QtGui.QWidget): if not self.mChatMessage[SHOWNAME]: self.name.setText(self.mChatMessage[CHARNAME]) else: - self.name.setText(self.mChatMessage[SHOWNAME]) + self.name.setText(decodeAOString(self.mChatMessage[SHOWNAME])) self.chatbox.hide() @@ -3989,17 +4007,21 @@ class GUI(QtGui.QWidget): return fChar = self.mChatMessage[CHARNAME] - f_emote = self.mChatMessage[ANIM] + fEmote = self.mChatMessage[ANIM] if not self.animIsEmpty: self.char.stop() if f_animState == 2: - self.char.playTalking(fChar, f_emote, self.scaling[0]) + self.char.playTalking(fChar, fEmote, self.scaling[0]) self.animState = 2 else: - self.char.playIdle(fChar, f_emote, self.scaling[0]) + self.char.playIdle(fChar, fEmote, self.scaling[0]) self.animState = 3 + + # TTS fun + if self.speaker: + self.speaker.say.emit(self.mChatMessage[CHATMSG], self.blip) def playEffect(self, fxName, fxSound, pChar, pFolder): effect = ini.get_effect(fxName, pChar, pFolder) @@ -4147,9 +4169,9 @@ class GUI(QtGui.QWidget): self.inlineBlueDepth += 1 if not self.entireMessageIsBlue and self.animState != 4: fChar = self.mChatMessage[CHARNAME] - f_emote = self.mChatMessage[ANIM] + fEmote = self.mChatMessage[ANIM] if not self.animIsEmpty: - self.char.playIdle(fChar, f_emote, self.scaling[0]) + self.char.playIdle(fChar, fEmote, self.scaling[0]) elif fCharacter == ")" and not self.nextCharacterIsNotSpecial and self.inlineColorStack: if self.inlineColorStack[-1] == INLINE_BLUE: @@ -4164,8 +4186,8 @@ class GUI(QtGui.QWidget): if not self.entireMessageIsBlue: if self.inlineBlueDepth == 0 and self.animState != 4 and not (self.tickPos+1 >= len(fMessage)): fChar = self.mChatMessage[CHARNAME] - f_emote = self.mChatMessage[ANIM] - self.char.playTalking(fChar, f_emote, self.scaling[0]) + fEmote = self.mChatMessage[ANIM] + self.char.playTalking(fChar, fEmote, self.scaling[0]) else: self.nextCharacterIsNotSpecial = True self.tickPos -= 1 @@ -4520,13 +4542,19 @@ class GUI(QtGui.QWidget): del self.playerList[pid] else: # Update a player if pid in self.playerList: - self.playerList[pid][utype] = data - + _data = None + if isinstance(data, unicode) or isinstance(data, str): + _data = self.charList[int(data)][0] if data.isdigit() else decodeAOString(data) + else: + _dataInt, ok = data.toInt() + _data = self.charList[int(_dataInt)][0] if ok else data + self.playerList[pid][utype] = _data + item = self.playerItems.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith) if item: name = self.playerList[pid][0] - char = self.playerList[pid][1] - charName = self.playerList[pid][2] + char = self.playerList[pid][1] if len(self.playerList[pid]) > 1 else None + charName = self.playerList[pid][2] if len(self.playerList[pid]) > 2 else None text = "[%s]" % pid if char: text += " %s" % char @@ -4856,4 +4884,4 @@ class GUI(QtGui.QWidget): self.areaItems.item(i).setIcon(QtGui.QIcon(AO2XPpath + "icons/" + "house.png")) except Exception as e: print "[debug] Couldn't update areas. Details:" - print "[debug]", e \ No newline at end of file + print "[debug]", e diff --git a/mainmenu.py b/mainmenu.py index 7e74ef0..c214e92 100644 --- a/mainmenu.py +++ b/mainmenu.py @@ -9,11 +9,6 @@ import AOsocket import ini from constants import * -def decodeAOString(text): - return text.replace("", "%").replace("", "#").replace("", "#").replace("", "&").replace("", "$") -def encodeAOString(text): - return text.replace("%", "").replace("#", "").replace("&", "").replace("$", "") - class PicButton(QtGui.QAbstractButton): def __init__(self, pixmap, parent=None): super(PicButton, self).__init__(parent) @@ -507,7 +502,6 @@ class AOServerInfo(QtCore.QThread): got_stuff = True elif header == "decryptor": - #self.tcp.send("HI#AO2XP %s#%%" % hardware.get_hdid()) self.tcp.send("HI#%s#%%" % hardware.get_hdid()) elif header == "ASS": # ha ha ha... @@ -519,7 +513,7 @@ class AOServerInfo(QtCore.QThread): elif header == "FL": features = network[1:] - print features + # print features elif header == 'BD': reason = network[1].decode("utf-8") if len(network) > 1 else "Failed to receive ban reason (old server version?)" # new in AO2 2.6 @@ -637,9 +631,9 @@ class AOServerInfo(QtCore.QThread): elif header == 'CT': if self.disconnect: continue - name = network[1].decode("utf-8").replace('', '$').replace('', '%').replace('', '&').replace('', '#').replace('', '#') - chatmsg = network[2].decode("utf-8").replace('', '$').replace('', '%').replace('', '&').replace('', '#').replace('', '#') - joinOOC.append("%s: %s" % (name, chatmsg)) + name = decodeAOString(network[1].decode('utf-8')) + chatmsg = decodeAOString(network[2].decode('utf-8').replace("\n", "
")) + joinOOC.append("%s: %s" % (name, chatmsg.replace("<", "<").replace("<br />","
") if len(network) > 3 and network[3] == "0" else chatmsg)) elif header == 'PU': del network[0] diff --git a/packets.py b/packets.py index 94e7ace..517ba9e 100644 --- a/packets.py +++ b/packets.py @@ -50,7 +50,7 @@ def handlePackets(caller, total, record=True): caller.OOC_Log.emit("%s: %s" % (name, chatmsg.replace("<", "<").replace("<br />","
") if len(network) > 3 and network[3] == "0" else chatmsg)) elif header == 'PV': - caller.parent.myChar = int(network[3]) if network[3] else 0 + caller.parent.myChar = int(network[3]) caller.parent.charSelect.hide() caller.newChar.emit(caller.parent.charList[caller.parent.myChar][0]) diff --git a/tts.py b/tts.py new file mode 100644 index 0000000..049a69b --- /dev/null +++ b/tts.py @@ -0,0 +1,54 @@ +from PyQt4 import QtCore +import random + +# WIP - DON'T USE + +class SpeechThread(QtCore.QThread): + say = QtCore.pyqtSignal(unicode, str) + interrupt = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super(SpeechThread, self).__init__(parent) + self._queue = [] + self._running = True + self.say.connect(self._enqueue) + self.interrupt.connect(self._interrupt) + self.maleVoices = [0, 1, 4, 7] + self.femaleVoices = [5, 6, 8, 9, 10] + self.speaker = None + + def run(self): + import win32com.client + import pythoncom + pythoncom.CoInitialize() + + self.speaker = win32com.client.Dispatch("SAPI.SpVoice") + voices = self.speaker.GetVoices() + + while self._running: + if self._queue: + text, gender = self._queue.pop(0) + if "http" in text: + continue + if "female" in gender: + self.speaker.Voice = voices.Item(random.choice(self.femaleVoices)) + else: + self.speaker.Voice = voices.Item(random.choice(self.maleVoices)) + text = unicode(text.toUtf8(), 'utf-8') + self.speaker.Speak(text, 1) + else: + self.msleep(20) + + pythoncom.CoUninitialize() + + def _interrupt(self): + if self.speaker: + self.speaker.Speak("", 2) + self._queue[:] = [] + + def _enqueue(self, text, gender): + self._queue.append([text, gender]) + + def stop(self): + self._interrupt() + self._running = False \ No newline at end of file