diff --git a/README.md b/README.md
index 50b6caa..706bf14 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# AO2XP 2.9.3
+# AO2XP 2.9.5
This is an alternative Attorney Online 2 client, developed in **Python 2.7**,
specifically made for older computers running Windows XP that cannot run the
diff --git a/demo.py b/demo.py
index f7d10a1..6e83253 100644
--- a/demo.py
+++ b/demo.py
@@ -5,15 +5,18 @@ from bisect import bisect_left
class DemoPlayer(QtCore.QObject):
MS_Chat = QtCore.pyqtSignal(list)
- newChar = QtCore.pyqtSignal(str)
+ newChar = QtCore.pyqtSignal(int)
newBackground = QtCore.pyqtSignal(str, bool)
IC_Log = QtCore.pyqtSignal(str)
OOC_Log = QtCore.pyqtSignal(str)
- charSlots = QtCore.pyqtSignal()
+ charSlots = QtCore.pyqtSignal(list)
loadAllEvidence = QtCore.pyqtSignal(list)
rainbowColor = QtCore.pyqtSignal(str)
updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
timerUpdate = QtCore.pyqtSignal(int, int, int)
+ authStatusChanged = QtCore.pyqtSignal(int)
+ updateAreaList = QtCore.pyqtSignal(list)
+ setCharList = QtCore.pyqtSignal(list)
def __init__(self, parent):
super(DemoPlayer, self).__init__(parent)
diff --git a/gameview.py b/gameview.py
index 285de49..7593625 100644
--- a/gameview.py
+++ b/gameview.py
@@ -1,28 +1,22 @@
-import thread, time, os, urllib, random, re, platform, subprocess
-import charselect, ini, AOsocket, images, packets, demo, buttons
+# This is the main file where everything happens. Honestly, it sucks and the
+# thing is so complex and unsafe that I'm surprised it even works. I wish for
+# a simpler client. ~ cidoku
+import thread, time, os, urllib, random, platform, subprocess
from os.path import exists, basename
-from ConfigParserEdit import ConfigParser
-from constants import *
from collections import OrderedDict
-from pybass_constants import *
-from PyQt4 import QtGui, QtCore
from functools import partial
from ctypes import create_string_buffer
from urllib2 import Request, urlopen
+from PyQt4 import QtGui, QtCore
+from ConfigParserEdit import ConfigParser
+from constants import *
+from pybass_constants import BASS_ATTRIB_VOL, BASS_ACTIVE_PAUSED, BASS_STREAM_AUTOFREE, BASS_SAMPLE_LOOP
+import charselect, ini, images, packets, demo, buttons, audio
DOWNLOAD_BLACKLIST = []
-
-URL_REGEX = r"https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)"
-
bucket = ""
-def delay(msec):
- dieTime = QtCore.QTime.currentTime().addMSecs(msec)
-
- while QtCore.QTime.currentTime() < dieTime:
- QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
-
def getCharIni(char, section, value, default=""):
tempini = ConfigParser()
return ini.read_ini(BASE_PATH + 'characters/' + char.lower() + '/char.ini', section, value, default)
@@ -242,7 +236,6 @@ class ChatLogs(QtGui.QTextEdit):
class AOCharMovie(QtGui.QLabel):
done = QtCore.pyqtSignal()
- usePillow = 0
pillowFrames = []
pillowFrame = 0
pillowSpeed = 0
@@ -289,7 +282,7 @@ class AOCharMovie(QtGui.QLabel):
def setFlipped(self, flip):
self.mFlipped = flip
-
+
def setAlignPos(self, pos):
if pos == "def":
self.setAlignment(QtCore.Qt.AlignLeft)
@@ -298,6 +291,21 @@ class AOCharMovie(QtGui.QLabel):
else:
self.setAlignment(QtCore.Qt.AlignCenter)
+ def findSprite(self, char, emote, prefix):
+ bases = [
+ "{char}/{prefix}{emote}",
+ "{char}/{emote}",
+ "{char}/{prefix}/{emote}"
+ ]
+ exts = [".apng", ".png", ".gif", ".webp"]
+
+ for base in bases:
+ for ext in exts:
+ path = BASE_PATH + "characters/" + base.format(char=char, prefix=prefix, emote=emote) + ext
+ if exists(path):
+ return path, ext
+ return None
+
def play(self, pChar, pEmote, emotePrefix, scaling = SCALING_AUTO, singleFrameDuration = -1):
if not len(pEmote):
return
@@ -319,118 +327,51 @@ class AOCharMovie(QtGui.QLabel):
pChar = pChar.lower()
pEmote = pEmote.lower()
- apngPath = testPath(
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/" + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/(a)" + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/(b)" + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/(a)/" + pEmote + ".apng",
- BASE_PATH + "characters/" + pChar + "/(b)/" + pEmote + ".apng"
- )
-
placeholderPath = AO2XPpath + "themes/default/oldplaceholder.gif"
- imgPath = ""
+ imgPath, ext = self.findSprite(pChar, pEmote, emotePrefix)
- if apngPath:
- imgPath = apngPath
- self.usePillow = 1
- else:
- pngPath = testPath(
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/" + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/(a)" + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/(b)" + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/(a)/" + pEmote + ".png",
- BASE_PATH + "characters/" + pChar + "/(b)/" + pEmote + ".png"
- )
-
- if pngPath:
- imgPath = pngPath
- self.usePillow = 0
+ if not imgPath:
+ if self.prevGifPath:
+ imgPath = self.prevGifPath
else:
- webpPath = testPath(
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/" + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/(a)" + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/(b)" + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/(a)/" + pEmote + ".webp",
- BASE_PATH + "characters/" + pChar + "/(b)/" + pEmote + ".webp"
- )
-
- if webpPath:
- imgPath = webpPath
- self.usePillow = 2
- else:
- gifPath = testPath(
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/" + emotePrefix + "/" + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/" + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/(a)" + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/(b)" + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/(a)/" + pEmote + ".gif",
- BASE_PATH + "characters/" + pChar + "/(b)/" + pEmote + ".gif"
- )
-
- if gifPath:
- imgPath = gifPath
- self.usePillow = 0
- else:
- if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
- pass
- # url = "base/characters/" + pChar.lower() + "/" + emotePrefix + pEmote.lower() + ".gif"
- # url = url.replace(" ", "%20")
- # thread.start_new_thread(downloadThread, (url, gifPath))
-
- if exists(placeholderPath):
- imgPath = placeholderPath
- print "[debug] Sprite not found:", pChar, pEmote, emotePrefix
- else:
- imgPath = ""
- self.usePillow = 0
-
- if imgPath == "":
- imgPath = self.prevGifPath
- # Second check just in case
- if imgPath == "":
if exists(placeholderPath):
imgPath = placeholderPath
- print "[debug] Sprite not found: ", pChar, pEmote, emotePrefix
+ print "[debug] Sprite not found:", pChar, pEmote, emotePrefix
else:
imgPath = "placeholder.png"
+ # if ini.read_ini_bool("AO2XP.ini", "General", "download characters"):
+ # url = "base/characters/" + pChar.lower() + "/" + emotePrefix + pEmote.lower() + ".gif"
+ # url = url.replace(" ", "%20")
+ # thread.start_new_thread(downloadThread, (url, gifPath))
else:
self.prevGifPath = imgPath
- #print "[debug]", pChar, emotePrefix, pEmote, "(!) path is null!" if imgPath == "" else imgPath
-
- if not self.usePillow:
- self.mMovie.setFileName(imgPath)
- self.mMovie.start()
- elif self.usePillow == 1: # apng
- self.pillowFrames = images.load_apng(apngPath)
- if len(self.pillowFrames) > 1:
- self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
- else:
- self.pillowTimer.start(int(singleFrameDuration * self.pillowSpeed))
-
- self.setPillowFrame()
- elif self.usePillow == 2: # webp
- try:
- self.pillowFrames = images.load_webp(webpPath)
+ if ext == ".apng":
+ self.pillowFrames = images.load_apng(imgPath)
if len(self.pillowFrames) > 1:
self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
else:
self.pillowTimer.start(int(singleFrameDuration * self.pillowSpeed))
self.setPillowFrame()
- except:
- if exists(placeholderPath):
- imgPath = placeholderPath
- print "[debug] Couldn't load webp sprite!"
- else:
- imgPath = "placeholder.png"
+ elif ext == ".webp":
+ try:
+ self.pillowFrames = images.load_webp(imgPath)
+ if len(self.pillowFrames) > 1:
+ self.pillowTimer.start(int(self.pillowFrames[0][1] * self.pillowSpeed))
+ else:
+ self.pillowTimer.start(int(singleFrameDuration * self.pillowSpeed))
+
+ self.setPillowFrame()
+ except:
+ if exists(placeholderPath):
+ imgPath = placeholderPath
+ print "[debug] Couldn't load webp sprite!"
+ else:
+ imgPath = "placeholder.png"
+ self.mMovie.setFileName(imgPath)
+ self.mMovie.start()
+ else:
self.mMovie.setFileName(imgPath)
self.mMovie.start()
@@ -668,13 +609,18 @@ class AOMovie(QtGui.QLabel):
self.pillowLabel.clear()
self.pillowLabel.hide()
self.hide()
+
+ def finish(self):
+ self.stop()
+ self.done.emit()
@QtCore.pyqtSlot(int)
def frameChange(self, nFrame):
if nFrame == self.mMovie.frameCount() - 1 and self.playOnce:
- delay(self.mMovie.nextFrameDelay())
- self.stop()
- self.done.emit()
+ QtCore.QTimer.singleShot(
+ self.mMovie.nextFrameDelay(),
+ self.finish
+ )
@QtCore.pyqtSlot()
def pillowFrameChange(self):
@@ -682,7 +628,7 @@ class AOMovie(QtGui.QLabel):
if len(self.pillowFrames) - 1 == self.pillowFrame:
if self.playOnce or (self.usePillow == 2 and self.pillowLoops+1 == self.webpLoops):
- delay(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
+ self.msleep(int(self.pillowFrames[self.pillowFrame][1] * self.pillowSpeed))
self.stop()
self.done.emit()
elif len(self.pillowFrames) > 1: # loop
@@ -746,7 +692,7 @@ class WTCEView(QtGui.QLabel):
super(WTCEView, self).move(self.parent.viewport.x(), self.parent.viewport.y())
super(WTCEView, self).resize(self.parent.viewport.size())
- def frameChange(self, frame):
+ def frameChange(self):
if self.movie.state() != QtGui.QMovie.Running:
return
img = self.movie.currentImage()
@@ -763,17 +709,30 @@ class WTCEView(QtGui.QLabel):
def showWTCE(self, wtce, variant=0):
self.finished()
+
+ wtcefile = BASE_PATH + "sounds/general/sfx-testimony2"
+ if self.parent.wtceSfx:
+ audio.freeHandle(self.parent.wtceSfx)
+
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:
+ wtcefile = BASE_PATH + "sounds/general/sfx-notguilty"
self.movie.setFileName(AO2XPpath + 'themes/default/notguilty.gif')
elif variant == 1:
+ wtcefile = BASE_PATH + "sounds/general/sfx-guilty"
self.movie.setFileName(AO2XPpath + 'themes/default/guilty.gif')
else:
return
+
+ 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.sliSoundVolume.value() / 100.0)
+
+ if self.parent.wtceSfx:
+ audio.playHandle(self.parent.wtceSfx, True)
self.show()
self.movie.start()
@@ -888,7 +847,7 @@ class EditEvidenceDialog(QtGui.QDialog):
def onBrowseClicked(self):
path = str(QtGui.QFileDialog.getOpenFileName(self, "Select an image", BASE_PATH + 'evidence', "Images (*.png)"))
if path:
- if not "/evidence/" in path.lower():
+ if "/evidence/" not in path.lower():
QtGui.QMessageBox.warning(self, 'Wrong directory', 'Please select a file from the "evidence" directory.')
self.onBrowseClicked()
return
@@ -921,16 +880,19 @@ class EditEvidenceDialog(QtGui.QDialog):
class TCPThread(QtCore.QThread):
connectionError = QtCore.pyqtSignal(str, str, str)
MS_Chat = QtCore.pyqtSignal(list)
- newChar = QtCore.pyqtSignal(str)
+ newChar = QtCore.pyqtSignal(int)
newBackground = QtCore.pyqtSignal(str, bool)
IC_Log = QtCore.pyqtSignal(str)
OOC_Log = QtCore.pyqtSignal(str)
- charSlots = QtCore.pyqtSignal()
+ charSlots = QtCore.pyqtSignal(list)
showCharSelect = QtCore.pyqtSignal()
loadAllEvidence = QtCore.pyqtSignal(list)
rainbowColor = QtCore.pyqtSignal(str)
updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
timerUpdate = QtCore.pyqtSignal(int, int, int)
+ authStatusChanged = QtCore.pyqtSignal(int)
+ updateAreaList = QtCore.pyqtSignal(list)
+ setCharList = QtCore.pyqtSignal(list)
send_attempts = 0
max_attempts = 5
@@ -944,7 +906,6 @@ class TCPThread(QtCore.QThread):
pingtimer = 150
rainbow = 0
sendtick = 0
- tempdata = ""
color = QtGui.QColor()
color.setHsv(rainbow, 255, 255)
while True:
@@ -961,7 +922,7 @@ class TCPThread(QtCore.QThread):
pingtimer -= 1
if pingtimer == 0:
- pingbefore = time.time()
+ # pingbefore = time.time()
self.parent.tcp.send('CH#%')
pingtimer = 150
@@ -1027,8 +988,7 @@ class Chatbox(QtGui.QLabel):
class GUI(QtGui.QWidget):
mainWindow = None
- # In theory 3 sounds may play at the same time: character, evidence sweep,
- # effect
+ # In theory 3 sounds may play at the same time: character, evidence sweep, effect
soundChannels = 3
soundChannel = 0
sound = []
@@ -1767,7 +1727,7 @@ class GUI(QtGui.QWidget):
self.tcp = None
self.demoPlayer = None
self.gotPV = False
-
+
# TTS fun
self.speaker = None
if getOption("General", "tts", False) == 'True':
@@ -1897,7 +1857,7 @@ class GUI(QtGui.QWidget):
move[e].move(*d[0:2])
else:
move[e].move(-500, -500)
-
+
if "courtroom" in design:
self.width = int(design["courtroom"][2])
self.height = int(design["courtroom"][3])
@@ -1914,7 +1874,7 @@ class GUI(QtGui.QWidget):
if "found_song_color" in design:
self.foundSongItemColor = QtGui.QColor(*[int(x) for x in design["found_song_color"]])
-
+
self.cbSlide.setVisible("slide_enable" in design)
self.cbBench.setVisible("ao2xp_desk" in design)
self.OOCLogin.setVisible("ao2xp_login" in design)
@@ -1950,7 +1910,7 @@ class GUI(QtGui.QWidget):
self.viewportScale = self.viewport.height() / float(192)
self.viewportRatio = self.viewport.width() / float(self.viewport.height())
-
+
# If the viewport is wide, align def/pro sprites properly
self.alignChars = (self.viewportRatio > 1.5)
@@ -2124,7 +2084,7 @@ class GUI(QtGui.QWidget):
def _themeCommon(self):
# IC input and demo slider
- viewportRight = max(self.viewport.x() + self.viewport.width(), 512)
+ # viewportRight = max(self.viewport.x() + self.viewport.width(), 512)
# IC options
gameTabsHeight = self.gameTabs.height() - self.gameTabs.findChild(QtGui.QTabBar).height()
@@ -2572,8 +2532,11 @@ class GUI(QtGui.QWidget):
self.tcp.send("RT#judgeruling#" +str(variant)+ "#%")
self.ICChatFocus()
- def onPVPacket(self, charName=""):
+ def onPVPacket(self, char=0):
QtGui.QApplication.restoreOverrideCursor()
+ self.myChar = char
+ self.charSelect.hide()
+ charName = self.charList[char][0]
self.setDisabled(False)
self.gotPV = True
if not self.swapping and charName:
@@ -3037,7 +3000,7 @@ class GUI(QtGui.QWidget):
if self.willDisconnect:
self.disconnectCommon()
self.mainWindow.returnToMenu()
-
+
def exitCommon(self):
self.disconnectCommon()
if self.speaker:
@@ -3045,6 +3008,7 @@ class GUI(QtGui.QWidget):
self.speaker.wait()
def disconnectCommon(self):
+ QtGui.QApplication.restoreOverrideCursor()
self.gotPV = False
self.charName = ""
self.onSwitchInventory(True)
@@ -3089,40 +3053,27 @@ class GUI(QtGui.QWidget):
def onOOCReturn(self):
text = encodeAOString(self.OOCInput.text()).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.......
+ if text.startsWith("/pos "): # why.......
ind = self.boxPositions.findText(str(text.split(" ")[1]))
if ind >= 0: self.boxPositions.setCurrentIndex(ind)
self.OOCInput.clear()
return
- if self.cbMockText.isChecked():
- text = mockString(text)
- if self.cbAutoCaps.isChecked():
- l = QtCore.QStringList(list(text))
- l[0] = l[0].toUpper()
+ # if self.cbMockText.isChecked():
+ # text = mockString(text)
+ # if self.cbAutoCaps.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.cbSpacing.isChecked():
- l = QtCore.QStringList(list(text))
- for i in range(1, len(l)+len(l)-1, 2):
- l.insert(i, " ")
- text = l.join("")
+ # 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.cbSpacing.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()
@@ -3614,7 +3565,7 @@ 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()
@@ -4024,7 +3975,7 @@ class GUI(QtGui.QWidget):
else:
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)
@@ -4555,7 +4506,7 @@ class GUI(QtGui.QWidget):
_dataInt, ok = data.toInt()
_data = self.charList[int(_dataInt)][0] if ok else decodeAOString(data)
self.playerList[pid][utype] = _data
-
+
item = self.playerItems.findItems("[%s]" % pid, QtCore.Qt.MatchStartsWith)
if item:
name = self.playerList[pid][0]
@@ -4607,39 +4558,11 @@ class GUI(QtGui.QWidget):
if self.onscreenTimerTimes == [0, 0, 0, 0, 0]:
self.onscreenTimer.stop()
-
- def onDemoClicked(self, item):
- fname = demo.getDemoFilename(self.demoItems, item)
-
- if not fname:
- return
-
- self.playerItems.clear()
- self.stopMusic()
- self.ICLog.clear()
- self.OOCLog.clear()
-
- if not self.demoPlaying:
- self.enableWidgets(True)
- self.tcpThread.stop()
- self.demoPlaying = True
-
- self.demoPlayer = demo.DemoPlayer(self)
- self.demoPlayer.MS_Chat.connect(self.netmsgMS)
- self.demoPlayer.newChar.connect(self.onPVPacket)
- self.demoPlayer.newBackground.connect(self.setBackground)
- self.demoPlayer.OOC_Log.connect(self.OOCLog.append)
- self.demoPlayer.IC_Log.connect(self.ICLog.append)
- self.demoPlayer.charSlots.connect(partial(self.charSelect.setCharList, self.charList))
- self.demoPlayer.loadAllEvidence.connect(self.loadAllEvidence)
- self.demoPlayer.updatePlayerList.connect(self.updatePlayerList)
- self.demoPlayer.rainbowColor.connect(self.text.setStyleSheet)
- self.demoPlayer.timerUpdate.connect(self.startPauseOnscreenTimers)
-
- self.demoPlayer.start(fname)
-
- def demoSeek(self, time):
- self.demoPlayer.seek(time)
+
+ def setCharSlots(self, data):
+ for i, value in enumerate(data):
+ self.charList[i][1] = int(value)
+ self.charSelect.setCharList(self.charList)
def startGame(self, tcp, playerList, charList, musicList, background, evidence, areas, features=[], joinOOC=[], hpList=[], webAO_bucket=""):
self.willDisconnect = False
@@ -4739,7 +4662,7 @@ class GUI(QtGui.QWidget):
self.boxEvidence.clear()
for evi in evidence:
self.boxEvidence.addItem(evi[0].strip())
-
+
if tcp.isWS and tcp.isSecure:
self.OOCLog.append("--- Using a secure connection ---")
@@ -4786,18 +4709,34 @@ class GUI(QtGui.QWidget):
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.charSlots.connect(self.setCharSlots)
self.tcpThread.showCharSelect.connect(self.charSelect.showCharSelect)
self.tcpThread.loadAllEvidence.connect(self.loadAllEvidence)
self.tcpThread.updatePlayerList.connect(self.updatePlayerList)
+ self.tcpThread.authStatusChanged.connect(self.authStatusChanged)
self.tcpThread.rainbowColor.connect(self.text.setStyleSheet)
self.tcpThread.timerUpdate.connect(self.startPauseOnscreenTimers)
+ self.tcpThread.updateAreaList.connect(self.updateAreaList)
self.tcpThread.start()
self.demoPlaying = False
self.startDemoRecorder(background)
self.ICChatInput.setFocus()
+
+ def newDemoPlayer(self):
+ self.demoPlayer = demo.DemoPlayer(self)
+ self.demoPlayer.MS_Chat.connect(self.netmsgMS)
+ self.demoPlayer.newChar.connect(self.onPVPacket)
+ self.demoPlayer.newBackground.connect(self.setBackground)
+ self.demoPlayer.OOC_Log.connect(self.OOCLog.append)
+ self.demoPlayer.IC_Log.connect(self.ICLog.append)
+ self.demoPlayer.charSlots.connect(self.setCharSlots)
+ self.demoPlayer.loadAllEvidence.connect(self.loadAllEvidence)
+ self.demoPlayer.updatePlayerList.connect(self.updatePlayerList)
+ self.demoPlayer.rainbowColor.connect(self.text.setStyleSheet)
+ self.demoPlayer.timerUpdate.connect(self.startPauseOnscreenTimers)
+ self.demoPlayer.setCharList.connect(self.onSCPacket)
def startDemo(self, fname):
self.playerList = []
@@ -4819,18 +4758,8 @@ class GUI(QtGui.QWidget):
self.sliBlipsVolume.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Blip volume", 100))
self.onImportEvidence(True)
-
- self.demoPlayer = demo.DemoPlayer(self)
- self.demoPlayer.MS_Chat.connect(self.netmsgMS)
- self.demoPlayer.newChar.connect(self.onPVPacket)
- self.demoPlayer.newBackground.connect(self.setBackground)
- self.demoPlayer.OOC_Log.connect(self.OOCLog.append)
- self.demoPlayer.IC_Log.connect(self.ICLog.append)
- self.demoPlayer.charSlots.connect(partial(self.charSelect.setCharList, self.charList))
- self.demoPlayer.loadAllEvidence.connect(self.loadAllEvidence)
- self.demoPlayer.updatePlayerList.connect(self.updatePlayerList)
- self.demoPlayer.rainbowColor.connect(self.text.setStyleSheet)
- self.demoPlayer.timerUpdate.connect(self.startPauseOnscreenTimers)
+
+ self.newDemoPlayer()
self.playerItems.clear()
self.stopMusic()
@@ -4850,6 +4779,28 @@ class GUI(QtGui.QWidget):
if bg:
self.demoRecorder.record([["BN", bg, ""]], encode=True)
+ def onDemoClicked(self, item):
+ fname = demo.getDemoFilename(self.demoItems, item)
+
+ if not fname:
+ return
+
+ self.playerItems.clear()
+ self.stopMusic()
+ self.ICLog.clear()
+ self.OOCLog.clear()
+
+ if not self.demoPlaying:
+ self.enableWidgets(True)
+ self.tcpThread.stop()
+ self.demoPlaying = True
+ self.newDemoPlayer()
+
+ self.demoPlayer.start(fname)
+
+ def demoSeek(self, time):
+ self.demoPlayer.seek(time)
+
def enableWidgets(self, demo = False):
for widget in [
self.OOCInput, self.btnCallMod,
@@ -4859,10 +4810,11 @@ class GUI(QtGui.QWidget):
self.tabMusic, self.boxEmotes, self.boxPositions,
self.cbFlip, self.cbPreanim, self.cbNoInterrupt,
self.boxEffects, self.cbSlide, self.cbBench,
- self.cbAdditive, self.areaItems,
- self.boxColors, self.btnDefenseBar.btnMinus, self.btnProsecutionBar.btnMinus,
- self.btnDefenseBar.btnPlus, self.btnProsecutionBar.btnPlus, self.btnWitnessTestimony,
- self.btnCrossExamination, self.btnNotGuilty, self.btnGuilty,
+ self.cbAdditive, self.areaItems, self.boxSounds, self.boxColors,
+ self.btnDefenseBar.btnMinus, self.btnProsecutionBar.btnMinus,
+ self.btnDefenseBar.btnPlus, self.btnProsecutionBar.btnPlus,
+ self.btnWitnessTestimony, self.btnCrossExamination,
+ self.btnNotGuilty, self.btnGuilty,
self.btnRealization, self.btnShake,
]:
widget.setEnabled(not demo)
@@ -4875,7 +4827,35 @@ class GUI(QtGui.QWidget):
else:
self.btnChangeChar.setText('Switch &character')
- def updateAreaList(self):
+ def updateAreaList(self, data=None):
+ if data:
+ kind = int(data[0])
+ self.areas[kind] = [data[i] for i in range(1, len(data))]
+
+ # This is much harder than doing it during the handshake because of
+ # the way the music list is implemented
+ if self.noARUP:
+ self.noARUP = False
+ self.areasLen = len(self.areas[kind])
+ print '[client]', 'The server has %d areas' % self.areasLen
+
+ if self.areasLen:
+ for i in range(self.areasLen):
+ area_key, area_val = self.musicList.items()[0]
+ self.areas[4].append(area_val)
+
+ areaitem = QtGui.QListWidgetItem()
+ self.areaItems.addItem(areaitem)
+
+ for j in range(4):
+ if j != kind:
+ self.areas[j].append("")
+
+ # Remove the area from the music list
+ self.musicList.popitem(False)
+
+ self.loadAllMusic()
+
try:
for i in range(self.areasLen):
areaPlayers = self.areas[0][i]
@@ -4895,3 +4875,20 @@ class GUI(QtGui.QWidget):
except Exception as e:
print "[debug] Couldn't update areas. Details:"
print "[debug]", e
+
+ def authStatusChanged(self, status):
+ statusStrings = ["You have logged out", "Wrong password", "Logged in"]
+ if status == 1:
+ self.login = True
+ self.btnPlayerKick.setDisabled(False)
+ self.btnPlayerBan.setDisabled(False)
+ self.OOCLogin.setText("Lo&g out")
+ elif status == -1:
+ self.login = False
+ self.btnPlayerKick.setDisabled(True)
+ self.btnPlayerBan.setDisabled(True)
+ self.OOCLogin.setText("Lo&gin")
+ self.OOCLog.append("%s" % (statusStrings[status+1]))
+
+ def onSCPacket(self, data):
+ self.charList = data
\ No newline at end of file
diff --git a/mainmenu.py b/mainmenu.py
index 6ca52e5..e8d3714 100644
--- a/mainmenu.py
+++ b/mainmenu.py
@@ -345,10 +345,8 @@ class MasterServer(QtCore.QThread):
def run(self):
try:
- tempdata = ""
self.msHttp = requests.get("http://servers.aceattorneyonline.com/servers")
self.msMotd = requests.get("http://servers.aceattorneyonline.com/motd")
-
if self.msHttp.ok: self.gotServers.emit(json.loads(self.msHttp.content))
if self.msMotd.ok: self.gotOOCMsg.emit(self.msMotd.content)
except Exception as e:
diff --git a/packets.py b/packets.py
index fe9cddf..4b9722f 100644
--- a/packets.py
+++ b/packets.py
@@ -50,15 +50,14 @@ 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])
- caller.parent.charSelect.hide()
- caller.newChar.emit(caller.parent.charList[caller.parent.myChar][0])
+ caller.newChar.emit(int(network[3]))
elif header == 'LE':
del network[0]
caller.loadAllEvidence.emit([evi.split('&') for evi in network])
elif header == 'ZZ':
+ # TODO: Remove from tcp thread
if caller.parent.modcall:
audio.freeHandle(caller.parent.modcall)
caller.parent.modcall = audio.loadHandle(0, "mod_call.wav", 0, 0, 0)
@@ -69,31 +68,14 @@ def handlePackets(caller, total, record=True):
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()
+ caller.charSlots.emit(network)
elif header == 'RT':
testimony = network[1]
- wtcefile = BASE_PATH + "sounds/general/sfx-testimony2"
- if caller.parent.wtceSfx:
- audio.freeHandle(caller.parent.wtceSfx)
-
- if testimony == 'judgeruling':
- variant = int(network[2])
- if variant == 0:
- wtcefile = BASE_PATH + "sounds/general/sfx-notguilty"
- elif variant == 1:
- wtcefile = BASE_PATH + "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.sliSoundVolume.value() / 100.0)
- if caller.parent.wtceSfx:
- audio.playHandle(caller.parent.wtceSfx, True)
+ variant = int(network[2]) if testimony == 'judgeruling' else 0
caller.parent.wtceSignal.emit(testimony, variant)
elif header == 'HP':
@@ -102,31 +84,22 @@ def handlePackets(caller, total, record=True):
caller.parent.healthbars.emit(kind, health)
elif header == 'KK':
+ # TODO: Show message from GUI thread
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':
+ # TODO: Show message from GUI thread
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)
+ # TODO: Show message from GUI thread
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.btnPlayerKick.setDisabled(False)
- caller.parent.btnPlayerBan.setDisabled(False)
- caller.parent.OOCLogin.setText("Lo&g out")
- elif status == -1:
- caller.parent.login = False
- caller.parent.btnPlayerKick.setDisabled(True)
- caller.parent.btnPlayerBan.setDisabled(True)
- caller.parent.OOCLogin.setText("Lo&gin")
- caller.OOC_Log.emit("%s" % (statusStrings[status+1]))
+ caller.authStatusChanged.emit(int(network[1]))
# elif header == "CHECK": #ping
# pingafter = time.time()
@@ -145,33 +118,7 @@ def handlePackets(caller, total, record=True):
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.noARUP:
- caller.parent.noARUP = False
- caller.parent.areasLen = len(caller.parent.areas[kind])
- print '[client]', 'The server has %d areas' % caller.parent.areasLen
-
- if caller.parent.areasLen:
- for i in range(caller.parent.areasLen):
- 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(4):
- if j != kind:
- caller.parent.areas[j].append("")
-
- # Remove the area from the music list
- caller.parent.musicList.popitem(False)
-
- caller.parent.loadAllMusic()
-
- caller.parent.updateAreaList()
+ caller.updateAreaList.emit(network)
elif header == 'TI':
del network[0]
@@ -186,4 +133,4 @@ def handlePackets(caller, total, record=True):
# 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
+ caller.setCharList.emit([ [char.split('&')[0].decode('utf-8'), 0, "male", True ] for char in network ])
\ No newline at end of file