AO2XP/mainmenu.py

607 lines
20 KiB
Python
Raw Normal View History

2019-04-03 10:57:23 -04:00
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
2020-08-06 09:48:04 -04:00
import socket, thread, time, random, traceback, hardware
2019-04-03 10:57:23 -04:00
from os.path import exists
2020-08-01 22:15:07 -04:00
AOpath = "base/"
#AOpath = "I:/aovanilla1.7.5/client/base/"
2019-04-03 10:57:23 -04:00
class PicButton(QtGui.QAbstractButton):
def __init__(self, pixmap, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawPixmap(event.rect(), self.pixmap)
def sizeHint(self):
return self.pixmap.size()
def setPixmap(self, pixmap):
self.pixmap = pixmap
class lobby(QtGui.QWidget):
gamewindow = None
tab = 0
def __init__(self, parent=None):
super(lobby, self).__init__(parent)
self.can_connect = False
self.svclicked = None
self.gamewindow = parent
2020-08-01 22:15:07 -04:00
self.pix_lobby = QtGui.QPixmap(AOpath+'themes/default/lobbybackground.png')
self.pix_btn_public = QtGui.QPixmap(AOpath+'themes/default/publicservers.png')
self.pix_btn_favs = QtGui.QPixmap(AOpath+'themes/default/favorites.png')
self.pix_btn_refresh = QtGui.QPixmap(AOpath+'themes/default/refresh.png')
self.pix_btn_addfav = QtGui.QPixmap(AOpath+'themes/default/addtofav.png')
self.pix_btn_connect = QtGui.QPixmap(AOpath+'themes/default/connect.png')
self.pix_connecting = QtGui.QPixmap(AOpath+'themes/default/loadingbackground.png')
2019-04-03 10:57:23 -04:00
if exists(AOpath+'serverlist.txt'):
with open(AOpath+'serverlist.txt') as file:
self.favoriteslist = [line.rstrip().split(':') for line in file]
else:
self.favoriteslist = ['127.0.0.1:27017:your server (port 27017)'.split(':'), '0.0.0.0:27017:serverlist.txt not found on base folder'.split(':')]
self.lobbyimg = QtGui.QLabel(self)
self.lobbyimg.setPixmap(self.pix_lobby)
self.lobbyimg.show()
self.connectingimg = QtGui.QLabel(self)
self.connectingimg.setPixmap(self.pix_connecting)
self.connectingimg.hide()
self.clientver = QtGui.QLabel(self)
2020-08-01 22:15:07 -04:00
self.clientver.setText('AO2XP 1.4 by Headshot')
2019-04-03 10:57:23 -04:00
self.clientver.resize(self.clientver.sizeHint())
self.clientver.move(self.pix_lobby.size().width() - self.clientver.size().width(), 0)
self.settingsbtn = QtGui.QPushButton(self)
self.settingsbtn.setText("Settings")
self.settingsbtn.resize(self.settingsbtn.sizeHint())
self.settingsbtn.move(self.clientver.x() - self.settingsbtn.size().width() - 8, 0)
self.settingsbtn.clicked.connect(self.onSettingsClicked)
self.btn_public = PicButton(self.pix_btn_public, self)
self.btn_public.resize(self.btn_public.sizeHint())
self.btn_public.move(46, 88)
self.btn_public.clicked.connect(self.onClicked_public)
self.btn_favs = PicButton(self.pix_btn_favs, self)
self.btn_favs.resize(self.btn_favs.sizeHint())
self.btn_favs.move(164, 88)
self.btn_favs.clicked.connect(self.onClicked_favs)
self.btn_refresh = PicButton(self.pix_btn_refresh, self)
self.btn_refresh.resize(self.btn_refresh.sizeHint())
self.btn_refresh.move(56, 381)
self.btn_refresh.clicked.connect(self.onClicked_refresh)
self.btn_addfav = PicButton(self.pix_btn_addfav, self)
self.btn_addfav.resize(self.btn_addfav.sizeHint())
self.btn_addfav.move(194, 381)
self.btn_addfav.clicked.connect(self.onClicked_addfav)
self.btn_connect = PicButton(self.pix_btn_connect, self)
self.btn_connect.resize(self.btn_connect.sizeHint())
self.btn_connect.move(332, 381)
self.btn_connect.clicked.connect(self.onClicked_connect)
self.serverlist = QtGui.QListWidget(self)
self.serverlist.resize(286, 240)
self.serverlist.move(20, 125)
self.serverlist.setStyleSheet("background-color: rgb(114, 114, 114)")
self.serverlist.itemClicked.connect(self.onClicked_serverlist)
self.onlineplayers = QtGui.QLabel(self)
self.onlineplayers.setStyleSheet('color: white')
self.onlineplayers.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)
self.onlineplayers.setText(random.choice(['hi', 'oh, welcome back', 'hello', 'click on a server to begin', 'yo, how you doing?']))
self.onlineplayers.move(336, 91)
self.onlineplayers.resize(173, 16)
self.serverinfo = QtGui.QTextEdit(self)
2020-08-03 20:28:25 -04:00
self.serverinfo.setReadOnly(True)
2019-04-03 10:57:23 -04:00
self.serverinfo.setStyleSheet("color: white; background-color: black")
self.serverinfo.move(337, 109)
self.serverinfo.resize(173, 245)
self.connectcancel = QtGui.QPushButton(self)
self.connectcancel.setText('Cancel')
self.connectcancel.resize(80, 20)
self.connectcancel.move(220, 220)
self.connectcancel.clicked.connect(self.onClicked_cancelconnect)
self.connectcancel.hide()
self.actual_serverlist = []
self.lobbychatlog = QtGui.QTextEdit(self)
self.lobbychatlog.setReadOnly(True)
self.lobbychatlog.setGeometry(2, 445, 513, 198)
self.lobbychatlog.setStyleSheet('background-color: rgb(139, 139, 139);')
self.lobbychatlog.textChanged.connect(self.lobbychatlog_update)
self.whitecolor = QtGui.QColor(255, 255, 255)
self.font = QtGui.QFont()
self.font.setFamily(QtCore.QString.fromUtf8('Arial'))
self.font.setBold(True)
self.font.setPointSize(14)
self.connectprogress = QtGui.QLabel(self)
self.connectprogress.hide()
self.connectprogress.setStyleSheet('color: rgb(255, 128, 0);')
self.connectprogress.setFont(self.font)
self.connectprogress.setText('Connecting...')
self.connectprogress.resize(300, 95)
self.connectprogress.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)
self.connectprogress.move(135-20, 92)
self.oocname = 'Name'
self.oocnameinput = QtGui.QLineEdit(self)
self.oocnameinput.setText(self.oocname)
self.oocnameinput.move(0, 646)
self.oocnameinput.resize(91, 19)
self.oocnameinput.setStyleSheet('background-color: rgb(87, 87, 87);')
self.oocnameinput.textChanged.connect(self.setoocname)
self.lobbychatinput = QtGui.QLineEdit(self)
self.lobbychatinput.setPlaceholderText("Say something...")
self.lobbychatinput.move(90, 646)
self.lobbychatinput.resize(427, 19)
self.lobbychatinput.setStyleSheet('background-color: rgb(87, 87, 87);')
self.lobbychatinput.returnPressed.connect(self.lobby_sendchat)
2020-08-06 09:48:04 -04:00
self.aoserverinfo = AOServerInfo()
self.aoserverinfo.moveToGameSignal.connect(self.moveToGame)
self.aoserverinfo.msgbox_signal.connect(self.showMessageBox)
self.aoserverinfo.setOnlinePlayers.connect(self.onlineplayers.setText)
self.aoserverinfo.returnToLobby.connect(self.onClicked_cancelconnect)
self.aoserverinfo.setConnectProgress.connect(self.connectprogress.setText)
self.aoserverinfo.readySoon.connect(self.connectcancel.hide)
self.aoserverinfo.setWindowTitle.connect(self.gamewindow.setWindowTitle)
self.aoserverinfo.canConnect.connect(self.canConnect)
self.masterserver = MasterServer()
self.masterserver.gotServers.connect(self.onGetServers)
self.masterserver.gotOOCMsg.connect(self.newOOCMessage)
self.masterserver.msgbox_signal.connect(self.showMessageBox)
self.masterserver.start()
def canConnect(self):
self.can_connect = True
2020-08-01 22:15:07 -04:00
def onGetServers(self, servers):
if self.tab == 0: self.serverlist.clear()
2020-08-01 22:15:07 -04:00
self.actual_serverlist = []
del servers[0]
del servers[-1]
for svcontent in servers:
server = svcontent.split('&')
del server[-1]
name = server[0].decode('utf-8')
desc = server[1].decode('utf-8')
if len(server) <= 2:
ip = '0.0.0.0'
port = 0
elif len(server) == 3:
ip = server[2]
port = 27017
elif len(server) == 4:
ip = server[2]
port = int(server[3])
serveritem = QtGui.QListWidgetItem(name)
if self.tab == 0: self.serverlist.addItem(serveritem)
2020-08-01 22:15:07 -04:00
self.actual_serverlist.append((ip, port, name, desc))
def moveToGame(self, stuff):
tcp, charlist, musiclist, background, evidence, areas, features, joinooc, hplist = stuff
self.move_to_game(tcp, charlist, musiclist, background, evidence, areas, features, joinooc, hplist)
2019-04-03 10:57:23 -04:00
def onSettingsClicked(self):
self.gamewindow.showSettings()
def showMessageBox(self, type, title, message):
if type == 0: #critical
return QtGui.QMessageBox.critical(self, title, message)
elif type == 1: #information
return QtGui.QMessageBox.information(self, title, message)
elif type == 2: #question
return QtGui.QMessageBox.question(self, title, message)
elif type == 3: #warning
return QtGui.QMessageBox.warning(self, title, message)
def onClicked_public(self):
self.tab = 0
self.serverlist.clear()
for sv in self.actual_serverlist:
self.serverlist.addItem(QtGui.QListWidgetItem(sv[2]))
def onClicked_favs(self):
self.tab = 1
self.serverlist.clear()
self.serverinfo.setText("")
for sv in self.favoriteslist:
self.serverlist.addItem(QtGui.QListWidgetItem(sv[2]))
def onClicked_refresh(self):
self.serverlist.clear()
if self.tab == 0:
try:
self.ms_tcp.send('ALL#%')
except:
self.lobbychatlog.append('failed to refresh server list')
elif self.tab == 1:
if exists(AOpath+'serverlist.txt'):
with open(AOpath+'serverlist.txt') as file:
self.favoriteslist = [ line.rstrip().split(':') for line in file ]
else:
self.favoriteslist = ['127.0.0.1:27017:your server (port 27017)'.split(':'), '0.0.0.0:27017:serverlist.txt not found on base folder'.split(':')]
def onClicked_addfav(self):
if self.tab == 1 or not self.svclicked:
if self.tab == 1:
QtGui.QMessageBox.information(self, "???", "Wait. That's illegal.")
return
for i in range(self.serverlist.count()):
if self.serverlist.item(i) == self.svclicked:
ip = self.actual_serverlist[i][0]
port = str(self.actual_serverlist[i][1])
name = self.actual_serverlist[i][2]
for sv in self.favoriteslist:
if sv[0] == ip and sv[1] == port:
return QtGui.QMessageBox.information(self, "Error", "This server already exists in your favorites list, named '%s'" % sv[2])
self.favoriteslist.append([ip, port, name])
with open(AOpath+'serverlist.txt', "a") as file:
file.write("%s:%s:%s\n" % (ip, port, name))
file.close()
def onClicked_connect(self):
if not self.can_connect:
return
self.connectprogress.setText('Connecting...')
self.connectingimg.show()
self.connectcancel.show()
self.connectprogress.show()
self.btn_public.hide()
self.btn_favs.hide()
self.btn_refresh.hide()
self.btn_addfav.hide()
self.btn_connect.hide()
self.serverlist.hide()
self.onlineplayers.hide()
self.serverinfo.hide()
self.clientver.hide()
self.settingsbtn.hide()
2020-08-06 09:48:04 -04:00
self.aoserverinfo.tcp.send('askchaa#%')
2019-04-03 10:57:23 -04:00
def onClicked_cancelconnect(self):
self.connectingimg.hide()
self.connectcancel.hide()
self.connectprogress.hide()
self.btn_public.show()
self.btn_favs.show()
self.btn_refresh.show()
self.btn_addfav.show()
self.btn_connect.show()
self.serverlist.show()
self.onlineplayers.show()
self.serverinfo.show()
self.clientver.show()
self.settingsbtn.show()
def onClicked_serverlist(self, item):
self.svclicked = item
self.can_connect = False
self.onlineplayers.setText('Retrieving...')
text = item.text()
print '[debug]', 'you clicked %s' % text
for i in range(self.serverlist.count()):
if self.serverlist.item(i) == item:
if self.tab == 0:
2020-08-06 09:48:04 -04:00
self.serverinfo.setText(self.actual_serverlist[i][3])
self.aoserverinfo.setIP(text, *self.actual_serverlist[i][:2])
2019-04-03 10:57:23 -04:00
print '[debug]', 'ind: ' + str(i) + ', ip: ' + self.actual_serverlist[i][0] + ', port: ' + str(self.actual_serverlist[i][1])
elif self.tab == 1:
2020-08-06 09:48:04 -04:00
self.aoserverinfo.setIP(text, *self.favoriteslist[i][:2])
2019-04-03 10:57:23 -04:00
print '[debug]', 'ind: ' + str(i) + ', ip: ' + self.favoriteslist[i][0] + ', port: ' + str(self.favoriteslist[i][1])
2020-08-06 09:48:04 -04:00
self.aoserverinfo.stop()
self.aoserverinfo.start()
def move_to_game(self, tcp, charlist, musiclist, background, evidence, areas, features=[], oocjoin=[], hplist=[]):
self.gamewindow.showGame(tcp, charlist, musiclist, background, evidence, areas, features, oocjoin, hplist)
def lobby_sendchat(self):
text = self.lobbychatinput.text().toUtf8()
self.ms_tcp.send('CT#' +self.oocname+ '#' + text + '#%')
self.lobbychatinput.clear()
def setoocname(self):
self.oocname = self.oocnameinput.text().toUtf8()
def lobbychatlog_update(self):
self.lobbychatlog.verticalScrollBar().setValue(self.lobbychatlog.verticalScrollBar().maximum())
def newOOCMessage(self, name, text):
self.lobbychatlog.append('%s: %s' % (name, text))
class MasterServer(QtCore.QThread):
gotServers = QtCore.pyqtSignal(list)
gotOOCMsg = QtCore.pyqtSignal(str, str)
msgbox_signal = QtCore.pyqtSignal(int, str, str)
def __init__(self):
super(MasterServer, self).__init__()
def run(self):
tempdata = ""
self.ms_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.ms_tcp.connect(('master.aceattorneyonline.com', 27016))
except:
return
while True:
contents = self.ms_tcp.recv(16384)
if len(contents) == 0:
print 'masterserver failure'
return
if not contents.endswith("%"):
tempdata += contents
continue
else:
if tempdata:
contents = tempdata + contents
tempdata = ""
temp = contents.split('%')
for msg in temp:
network = msg.split('#')
header = network[0]
if header == "servercheok":
self.ms_tcp.send("HI#AO2XP %s#%%ID#AO2XP by Headshot#1.4#%%" % hardware.get_hdid())
self.ms_tcp.send("ALL#%")
elif header == 'DOOM':
print 'banned from masterserver'
self.msgbox_signal.emit(0, "WHEEZE", "You are exiled from AO")
self.ms_tcp.close()
return
elif header == 'ALL':
self.gotServers.emit(network)
elif header == 'CT':
name = network[1].decode("utf-8").replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#').replace('<pound>', '#')
chatmsg = network[2].decode("utf-8").replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#').replace('<pound>', '#')
self.gotOOCMsg.emit(name, chatmsg)
class AOServerInfo(QtCore.QThread):
moveToGameSignal = QtCore.pyqtSignal(list)
msgbox_signal = QtCore.pyqtSignal(int, str, str)
setOnlinePlayers = QtCore.pyqtSignal(str)
setConnectProgress = QtCore.pyqtSignal(str)
returnToLobby = QtCore.pyqtSignal()
readySoon = QtCore.pyqtSignal()
setWindowTitle = QtCore.pyqtSignal(str)
canConnect = QtCore.pyqtSignal()
def __init__(self):
super(AOServerInfo, self).__init__()
self.ip = ""
self.port = 0
self.name = "jm"
self.disconnect = False
def setIP(self, name, ip, port):
self.ip = ip
self.port = int(port)
self.name = name
def stop(self):
self.disconnect = True
if self.isRunning():
self.terminate()
self.wait()
def run(self):
self.disconnect = False
self.tcp = socket.socket()
try:
self.tcp.connect((self.ip, self.port))
except:
self.setOnlinePlayers.emit("couldn't retrieve players")
return
2019-04-03 10:57:23 -04:00
self.tcp.settimeout(0.2)
2020-08-06 09:48:04 -04:00
tempdata = ""
gotChars = False
hplist = []
joinooc = []
areas = [[], [], [], []]
features = []
pingtimer = 150
readytick = -1
2019-04-03 10:57:23 -04:00
while True:
2020-08-06 09:48:04 -04:00
if self.disconnect:
try: self.tcp.close()
except: pass
return
2019-04-03 10:57:23 -04:00
pingtimer -= 1
if pingtimer == 0:
pingtimer = 150
self.tcp.send('CH#%')
if readytick > -1:
readytick -= 1
if readytick == 0:
readytick = -1
try:
2020-08-06 09:48:04 -04:00
self.moveToGameSignal.emit([self.tcp, charlist, musiclist, background, evidence, areas, features, joinooc, hplist])
2019-04-03 10:57:23 -04:00
except Exception as err:
2020-08-01 22:15:07 -04:00
self.msgbox_signal.emit(0, "Error caught while loading", traceback.format_exc(err))
2020-08-06 09:48:04 -04:00
self.returnToLobby.emit()
2019-04-03 10:57:23 -04:00
return
2020-08-06 09:48:04 -04:00
self.setWindowTitle.emit(self.name)
return
2019-04-03 10:57:23 -04:00
try:
contents = self.tcp.recv(16384)
except (socket.timeout, socket.error) as err:
error = err.args[0]
if error == "timed out" or error == 10035:
continue
else:
2020-08-06 09:48:04 -04:00
self.setOnlinePlayers.emit("Something wrong happened" if not got_stuff else "Connection lost")
return
2019-04-03 10:57:23 -04:00
if not contents.endswith("%"):
tempdata += contents
continue
else:
if tempdata:
contents = tempdata + contents
tempdata = ""
totals = contents.split('%')
for g in totals:
network = g.split('#')
header = network[0]
if header == 'PN':
players = int(network[1])
maxplayers = int(network[2])
2020-08-06 09:48:04 -04:00
self.canConnect.emit()
self.setOnlinePlayers.emit('%d/%d players online' % (players, maxplayers))
2019-04-03 10:57:23 -04:00
got_stuff = True
elif header == "decryptor":
2020-08-03 20:28:25 -04:00
self.tcp.send("HI#AO2XP %s#%%" % hardware.get_hdid())
2019-04-03 10:57:23 -04:00
elif header == "ID":
2020-08-01 22:15:07 -04:00
self.tcp.send("ID#AO2#69.1337.420#%") # need to send this to tsuserver3 servers in order to get feature list (FL)
2019-04-03 10:57:23 -04:00
elif header == "FL":
features = network[1:]
print features
elif header == 'BD':
2020-08-01 22:15:07 -04:00
reason = network[1].decode("utf-8") if len(network) > 1 else "Failed to receive ban reason (old server version?)" # new in AO2 2.6
2020-08-06 09:48:04 -04:00
self.setOnlinePlayers.emit('Banned')
2019-04-03 10:57:23 -04:00
self.msgbox_signal.emit(0, "Banned", "Reason:\n"+reason)
self.tcp.close()
2020-08-06 09:48:04 -04:00
return
2019-04-03 10:57:23 -04:00
elif header == 'SI':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
maxchars = int(network[1])
maxevidence = int(network[2])
maxmusic = int(network[3])
2020-08-06 09:48:04 -04:00
self.setConnectProgress.emit('Requesting character list (%d)...' % maxchars)
2019-04-03 10:57:23 -04:00
self.tcp.send('RC#%')
print '[client]', '%d characters, %d pieces of evidence and %d songs' % (maxchars, maxevidence, maxmusic)
elif header == 'SC':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
del network[0]
del network[len(network)-1]
2020-08-01 23:50:05 -04:00
gotChars = True
2019-04-03 10:57:23 -04:00
charlist = [ [char.split('&')[0], -1, "male"] for char in network ]
2020-08-06 09:48:04 -04:00
self.setConnectProgress.emit('Requesting music list (%d)...' % maxmusic)
2019-04-03 10:57:23 -04:00
self.tcp.send('RM#%')
print '[client]', 'received characters (%d)' % len(charlist)
elif header == 'SM':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
del network[0]
del network[len(network)-1]
musiclist = [music for music in network]
2020-08-06 09:48:04 -04:00
self.setConnectProgress.emit('Finishing...')
2019-04-03 10:57:23 -04:00
self.tcp.send('RD#%')
print '[client]', 'received songs (%d)' % len(musiclist)
elif header == 'CharsCheck':
2020-08-06 09:48:04 -04:00
if self.disconnect or not gotChars:
2019-04-03 10:57:23 -04:00
continue
network.pop(0)
network.pop(len(network)-1)
for i in range(len(network)):
charlist[i][1] = int(network[i])
elif header == 'BN':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
background = network[1]
print '[client]', 'courtroom background: %s' % background
elif header == 'LE':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
del network[0]
del network[len(network)-1]
if len(network) > 0:
if "<and>" in network[0]: #The Next Chapter actually does this sorcery...
evidence = [evi.split("<and>") for evi in network]
else:
evidence = [evi.split("&") for evi in network]
else:
evidence = []
for evi in evidence:
evi[0] = evi[0].decode("utf-8")
evi[1] = evi[1].decode("utf-8")
evi[2] = evi[2].decode("utf-8")
print '[client]', 'received evidence'
elif header == 'HP':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
del network[0]
del network[len(network)-1]
type = int(network[0])
health = int(network[1])
hplist.append([type, health])
elif header == "ARUP": #AO2 2.6 new feature: area update
del network[0]
del network[len(network)-1]
type = int(network[0])
if type == 0: #player count
areas[type] = [network[i] for i in range(1, len(network))]
else: #area status, casemakers or locked area
areas[type] = [network[i] for i in range(1, len(network))]
elif header == 'DONE':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
2020-08-06 09:48:04 -04:00
self.setConnectProgress.emit('Done, loading...')
self.readySoon.emit()
2019-04-03 10:57:23 -04:00
print '[client]', 'finished requesting data, loading game...'
readytick = 4
elif header == 'CT':
2020-08-06 09:48:04 -04:00
if self.disconnect:
2019-04-03 10:57:23 -04:00
continue
del network[0]
del network[len(network)-1]
name = network[0].decode("utf-8").replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#').replace('<pound>', '#')
chatmsg = network[1].decode("utf-8").replace('<dollar>', '$').replace('<percent>', '%').replace('<and>', '&').replace('<num>', '#').replace('<pound>', '#')
2020-08-06 09:48:04 -04:00
joinooc.append("%s: %s" % (name, chatmsg))