allow demo playback from main menu + quitting the demo player

This commit is contained in:
cidoku 2025-03-11 19:30:06 -03:00
parent 24e034b34e
commit 51b248cf76
5 changed files with 165 additions and 66 deletions

View File

@ -10,6 +10,8 @@ import audio as AUDIO
import ini
from constants import *
import gameview, mainmenu, options, demo
__builtin__.audio = AUDIO
del AUDIO
@ -48,6 +50,7 @@ class gamewindow(QtGui.QMainWindow):
self.setWindowFlags(QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowCloseButtonHint)
self.settingsgui = options.Settings(self)
self.demopickergui = demo.DemoPicker(self)
self.aboutgui = self.aboutBox()
def center(self):
@ -72,6 +75,9 @@ class gamewindow(QtGui.QMainWindow):
def showSettings(self):
self.settingsgui.showSettings()
def show_demo_picker(self):
self.demopickergui.show()
def aboutBox(self):
box = QtGui.QMessageBox()
box.setText("AO2XP %s\nRunning on %s %s %s (Python %s)\n\n2019-2025 headshot / cidoku" % (GAME_VERSION, platform.system(), platform.release(), platform.machine(), platform.python_version()))
@ -107,7 +113,6 @@ if not debugmode:
os.chdir(path.resourcePath()) # return to Resources folder
import gameview, mainmenu, options
# This hides stupid useless QT warnings
def handler(msg_type, msg_string):

64
demo.py
View File

@ -33,6 +33,7 @@ class DemoPlayer(QtCore.QObject):
self.last_bg = ""
def start(self, file):
self.paused = True
self.wait_timer.stop()
self.time = 0
@ -71,6 +72,7 @@ class DemoPlayer(QtCore.QObject):
self.parent.demoslider.setValue(self.time)
self.parent.demoslider.blockSignals(False)
self.time += 1
self.paused = False
if packet[0] == "wait":
if skip_wait:
@ -132,6 +134,10 @@ class DemoPlayer(QtCore.QObject):
if self.paused:
return
self.step()
def stop(self):
self.paused = True
self.wait_timer.stop()
class DemoRecorder():
def __init__(self):
@ -161,6 +167,46 @@ class DemoRecorder():
if encode:
line = line.encode('utf-8')
demofile.write(line)
class DemoPicker(QtGui.QDialog):
def __init__(self, parent):
super(DemoPicker, self).__init__()
self.setModal(True)
self.gamewindow = parent
self.parent = parent
self.setWindowTitle("Select a demo file...")
self.setFixedSize(480, 512)
self.setWindowIcon(QtGui.QIcon("AO2XP.ico"))
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint)
self.hide()
self.treeview = get_demo_treeview()
self.treeview.doubleClicked.connect(self.on_demo_click)
self.cancelbtn = QtGui.QPushButton()
self.cancelbtn.setText("Cancel")
self.cancelbtn.clicked.connect(self.hide)
main_layout = QtGui.QVBoxLayout(self)
btns_layout = QtGui.QHBoxLayout()
btns_layout.addWidget(self.cancelbtn, 0, QtCore.Qt.AlignRight)
main_layout.addWidget(self.treeview)
main_layout.addLayout(btns_layout)
self.cancelbtn.setFocus()
def on_demo_click(self, item):
fname = get_demo_fname(self.treeview, item)
if not fname:
return
self.gamewindow.gamewidget.start_demo(fname)
self.gamewindow.stackwidget.setCurrentWidget(self.gamewindow.gamewidget)
self.hide()
def get_demo_treeview():
demo_model = QtGui.QFileSystemModel();
@ -175,4 +221,20 @@ def get_demo_treeview():
for i in range(1, demo_model.columnCount()):
demo_treeview.hideColumn(i)
return demo_treeview
return demo_treeview
def get_demo_fname(treeview, item):
model = treeview.model()
if model.isDir(item):
return None
path = QtCore.QStringList()
while item.isValid():
fname = model.fileName(item)
if fname == "logs":
break
path.insert(0, fname)
item = item.parent()
return path.join("/")

View File

@ -912,6 +912,7 @@ class TCPThread(QtCore.QThread):
while True:
if self.stop_now:
self.parent.tcp.close()
self.parent.tcp = None
self.quit()
return
@ -1419,7 +1420,6 @@ class GUI(QtGui.QWidget):
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
@ -1580,6 +1580,7 @@ class GUI(QtGui.QWidget):
self.stream = 0
self.specialstream = 0
self.download_thread = None
self.tcp = None
# Finally, load the theme
self.width = 820
@ -2147,8 +2148,13 @@ class GUI(QtGui.QWidget):
self.tcp.send("ZZ#%")
def onClick_changeChar(self):
#self.tcp.send('RD#%')
self.charselect.showCharSelect()
if self.demo_playing:
self.inbox_timer.stop()
self.chat_tick_timer.stop()
self.disconnectCommon()
self.gamewindow.returnToMenu()
else:
self.charselect.showCharSelect()
def changeFlipCheck(self, on):
if on == 2:
@ -2285,11 +2291,16 @@ class GUI(QtGui.QWidget):
self.player_list.clear()
self.player_kick.setDisabled(True)
self.player_ban.setDisabled(True)
self.demo_recorder = None
self.ooclogin.setText("Lo&gin")
self.login = False
self.privateinv = False
self.tcp.close()
if self.tcp:
self.tcp.close()
if self.demo_player:
self.demo_player.stop()
self.demo_player = None
self.demo_recorder = None
self.demo_playing = False
self.stopMusic()
def onMusicClick(self, item):
@ -3691,37 +3702,37 @@ class GUI(QtGui.QWidget):
self.onscreen_timer.stop()
def on_demo_click(self, item):
model = self.demoitems.model()
if model.isDir(item):
fname = demo.get_demo_fname(self.demoitems, item)
if not fname:
return
path = QtCore.QStringList()
while item.isValid():
fname = model.fileName(item)
if fname == "logs":
break
path.insert(0, fname)
item = item.parent()
fname = path.join("/")
self.player_list.clear()
self.stopMusic()
self.iclog.clear()
self.ooclog.clear()
if not self.demo_playing:
for widget in [self.oocinput, self.callmodbtn, self.changechar, self.oocnameinput, self.ooclogin, self.gametab_evidence, self.gametab_msgqueue, self.gametab_iniswap, self.gametab_mute, self.gametab_pair, self.gametab_misc, self.gametab_players, self.gametab_music, self.emotedropdown, self.posdropdown, self.flipbutton, self.sfxbutton, self.nointerruptbtn, self.effectdropdown, self.slidebutton, self.deskbtn, self.additivebtn, self.areaitems, self.shownameedit, self.colordropdown]:
widget.setEnabled(False)
self.demoslider.setVisible(True)
self.icchatinput.setVisible(False)
self.enable_widgets(True)
self.tcpthread.stop()
self.demo_playing = True
self.demo_player = demo.DemoPlayer(self)
self.demo_player.MS_Chat.connect(self.netmsg_ms)
self.demo_player.newChar.connect(self.onPVPacket)
self.demo_player.newBackground.connect(self.setBackground)
self.demo_player.OOC_Log.connect(self.ooclog.append)
self.demo_player.IC_Log.connect(self.iclog.append)
self.demo_player.charSlots.connect(partial(self.charselect.setCharList, self.charlist))
self.demo_player.allEvidence.connect(self.allEvidence)
self.demo_player.updatePlayerList.connect(self.updatePlayerList)
self.demo_player.rainbowColor.connect(self.text.setStyleSheet)
self.demo_player.timerUpdate.connect(self.start_pause_timers)
self.demoplayer.start(fname)
self.demo_player.start(fname)
def demo_seek(self, time):
self.demoplayer.seek(time)
self.demo_player.seek(time)
def start_game(self, tcp, playerlist, charlist, musiclist, background, evidence, areas, features=[], oocjoin=[], hplist=[], webAO_bucket=""):
self.willDisconnect = False
@ -3863,17 +3874,8 @@ class GUI(QtGui.QWidget):
self.tcpthread.timerUpdate.connect(self.start_pause_timers)
self.tcpthread.start()
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)
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.allEvidence.connect(self.allEvidence)
self.demoplayer.updatePlayerList.connect(self.updatePlayerList)
self.demoplayer.rainbowColor.connect(self.text.setStyleSheet)
self.demoplayer.timerUpdate.connect(self.start_pause_timers)
self.demo_playing = False
self.enable_widgets()
self.start_demo_recorder(background)
self.icchatinput.setFocus()
@ -3899,30 +3901,27 @@ class GUI(QtGui.QWidget):
self.onImportEvidence(True)
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)
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.allEvidence.connect(self.allEvidence)
self.demoplayer.updatePlayerList.connect(self.updatePlayerList)
self.demoplayer.rainbowColor.connect(self.text.setStyleSheet)
self.demoplayer.timerUpdate.connect(self.start_pause_timers)
self.demo_player = demo.DemoPlayer(self)
self.demo_player.MS_Chat.connect(self.netmsg_ms)
self.demo_player.newChar.connect(self.onPVPacket)
self.demo_player.newBackground.connect(self.setBackground)
self.demo_player.OOC_Log.connect(self.ooclog.append)
self.demo_player.IC_Log.connect(self.iclog.append)
self.demo_player.charSlots.connect(partial(self.charselect.setCharList, self.charlist))
self.demo_player.allEvidence.connect(self.allEvidence)
self.demo_player.updatePlayerList.connect(self.updatePlayerList)
self.demo_player.rainbowColor.connect(self.text.setStyleSheet)
self.demo_player.timerUpdate.connect(self.start_pause_timers)
self.player_list.clear()
self.stopMusic()
self.iclog.clear()
self.ooclog.clear()
for widget in [self.oocinput, self.callmodbtn, self.changechar, self.oocnameinput, self.ooclogin, self.gametab_evidence, self.gametab_msgqueue, self.gametab_iniswap, self.gametab_mute, self.gametab_pair, self.gametab_misc, self.gametab_players, self.gametab_music, self.emotedropdown, self.posdropdown, self.flipbutton, self.sfxbutton, self.nointerruptbtn, self.effectdropdown, self.slidebutton, self.deskbtn, self.additivebtn, self.areaitems, self.shownameedit, self.colordropdown]:
widget.setEnabled(False)
self.demoslider.setVisible(True)
self.icchatinput.setVisible(False)
self.changechar.setText('Disconnect')
self.enable_widgets(True)
self.demo_playing = True
self.demoplayer.start(fname)
self.demo_player.start(fname)
def start_demo_recorder(self, bg):
if ini.read_ini_bool("AO2XP.ini", "General", "record demos", False):
@ -3930,4 +3929,27 @@ class GUI(QtGui.QWidget):
self.demo_recorder.start()
self.demo_recorder.record([["SC"] + [char[0] for char in self.charlist]], encode=True)
self.demo_recorder.record([["BN", bg, ""]], encode=True)
def enable_widgets(self, demo = False):
for widget in [
self.oocinput, self.callmodbtn,
self.oocnameinput, self.ooclogin, self.gametab_evidence,
self.gametab_msgqueue, self.gametab_iniswap, self.gametab_mute,
self.gametab_pair, self.gametab_misc, self.gametab_players,
self.gametab_music, self.emotedropdown, self.posdropdown,
self.flipbutton, self.sfxbutton, self.nointerruptbtn,
self.effectdropdown, self.slidebutton, self.deskbtn,
self.additivebtn, self.areaitems, self.shownameedit,
self.colordropdown, self.defensebar.minusbtn, self.prosecutionbar.minusbtn,
self.defensebar.plusbtn, self.prosecutionbar.plusbtn, self.wtcebtn_1,
self.wtcebtn_2, self.notguiltybtn, self.guiltybtn,
self.realizationbtn, self.shakebtn,
]:
widget.setEnabled(not demo)
self.demoslider.setVisible(demo)
self.icchatinput.setVisible(not demo)
if demo:
self.changechar.setText('Disconnect')
else:
self.changechar.setText('Switch &character')

View File

@ -76,6 +76,12 @@ class lobby(QtGui.QWidget):
self.settingsbtn.move(self.pix_lobby.size().width() - self.settingsbtn.size().width(), 0)
self.settingsbtn.clicked.connect(self.onSettingsClicked)
self.demobtn = QtGui.QPushButton(self)
self.demobtn.setText("Play a demo")
self.demobtn.resize(self.demobtn.sizeHint())
self.demobtn.move(self.settingsbtn.x() - self.demobtn.size().width(), 0)
self.demobtn.clicked.connect(self.on_demo_clicked)
self.btn_public = PicButton(self.pix_btn_public, self)
self.btn_public.resize(self.btn_public.sizeHint())
self.btn_public.move(46, 88)
@ -223,6 +229,9 @@ class lobby(QtGui.QWidget):
def onSettingsClicked(self):
self.gamewindow.showSettings()
def on_demo_clicked(self):
self.gamewindow.show_demo_picker()
def showMessageBox(self, type, title, message):
if type == 0: #critical
@ -298,14 +307,13 @@ class lobby(QtGui.QWidget):
self.onlineplayers.hide()
self.serverinfo.hide()
self.settingsbtn.hide()
self.demobtn.hide()
self.connectprogress.setText('Connecting...')
self.connectingimg.show()
self.connectcancel.show()
self.connectprogress.show()
self.aoserverinfo.tcp.send('askchaa#%')
# self.gamewindow.gamewidget.start_demo("test.demo")
# self.gamewindow.stackwidget.setCurrentWidget(self.gamewindow.gamewidget)
def onClicked_cancelconnect(self):
self.connectingimg.hide()
@ -320,6 +328,7 @@ class lobby(QtGui.QWidget):
self.onlineplayers.show()
self.serverinfo.show()
self.settingsbtn.show()
self.demobtn.show()
def onClicked_serverlist(self, item):
self.svclicked = item

View File

@ -344,15 +344,16 @@ class Settings(QtGui.QDialog):
self.gamewindow.gamewidget.text_wait_time = self.textstaytime.value()
self.gamewindow.gamewidget.slide_enabled = self.enableslide.isChecked()
if not (self.savelogs_state == self.savetolog.isChecked() and self.combinelogs_state == self.savetolog_combine.isChecked()):
self.gamewindow.gamewidget.ooclog.set_logfiles()
self.gamewindow.gamewidget.iclog.set_logfiles(self.gamewindow.gamewidget.ooclog.logfile)
if not self.savedemos_state == self.savedemos.isChecked():
if self.savedemos.isChecked():
self.gamewindow.gamewidget.start_demo_recorder()
else:
self.gamewindow.gamewidget.demo_recorder = None
if not self.gamewindow.gamewidget.demo_playing:
if not (self.savelogs_state == self.savetolog.isChecked() and self.combinelogs_state == self.savetolog_combine.isChecked()):
self.gamewindow.gamewidget.ooclog.set_logfiles()
self.gamewindow.gamewidget.iclog.set_logfiles(self.gamewindow.gamewidget.ooclog.logfile)
if not self.savedemos_state == self.savedemos.isChecked():
if self.savedemos.isChecked():
self.gamewindow.gamewidget.start_demo_recorder()
else:
self.gamewindow.gamewidget.demo_recorder = None
self.hide()