diff --git a/AO2XPbase/ao2xp_themes/default/theme.py b/AO2XPbase/ao2xp_themes/default/theme.py index d7fa037..775f8dd 100644 --- a/AO2XPbase/ao2xp_themes/default/theme.py +++ b/AO2XPbase/ao2xp_themes/default/theme.py @@ -1,14 +1,14 @@ -self.gamewindow.setFixedSize(714, 668) +self.gamewindow.setFixedSize(820, 730) -self.ooclog.setGeometry(714 - 288, 0, 288, 256) +self.ooclog.setGeometry(814 - 288, 0, 288, 248) self.oocnameinput.resize(self.oocnameinput.sizeHint().width() - 32, self.oocnameinput.sizeHint().height()) -self.oocnameinput.move(714 - 288, 256) +self.oocnameinput.move(814 - 288, 248) self.oocinput.resize(176, self.oocinput.sizeHint().height()) -self.oocinput.move(714 - 288 + self.oocnameinput.size().width(), 256) +self.oocinput.move(814 - 288 + self.oocnameinput.size().width(), 248) self.ooclogin.resize(48, 20) -self.ooclogin.move(714 - (self.ooclogin.size().width()), self.oocinput.y() + self.ooclogin.size().height()) +self.ooclogin.move(814 - (self.ooclogin.size().width()), self.oocinput.y() + self.ooclogin.size().height()) -self.musicitems.setGeometry(714 - 288, 348, 288, 320) +self.musicitems.setGeometry(814 - 288, 468, 288, 256) self.icLog.setGeometry(8, 8, 714 - 304 - 22, 212) @@ -53,7 +53,7 @@ self.pair_order.setGeometry(self.pairoffset.x(), self.pair_order_l.y()-4, 80, se self.spacebartext.move(self.mocktext.x(), self.mocktext.y()+24) self.autocaps.move(self.spacebartext.x(), self.spacebartext.y()+24) -self.gametabs.move(8, 402) +self.gametabs.move(8, 468) self.gametabs.resize(714 - 304, 256) self.musicslider.setGeometry(self.oocnameinput.x(), self.oocnameinput.y()+24, 192, 16) diff --git a/AO2XPbase/font/Ace_Name_Regular.ttf b/AO2XPbase/font/Ace_Name_Regular.ttf new file mode 100644 index 0000000..d5c6e88 Binary files /dev/null and b/AO2XPbase/font/Ace_Name_Regular.ttf differ diff --git a/AO2XPbase/font/Igiari.ttf b/AO2XPbase/font/Igiari.ttf new file mode 100644 index 0000000..9b7be36 Binary files /dev/null and b/AO2XPbase/font/Igiari.ttf differ diff --git a/AO2XPbase/font/license.txt b/AO2XPbase/font/license.txt new file mode 100644 index 0000000..a13fa44 --- /dev/null +++ b/AO2XPbase/font/license.txt @@ -0,0 +1,8 @@ +License for Igiari font + +This font was created by Caveras with FontStruct and is licensed +under a Creative Commons Attribution Non-commercial Share Alike +license. + +http://fontstruct.com/fontstructors/caveras +http://creativecommons.org/licenses/by-nc-sa/3.0/ \ No newline at end of file diff --git a/AO2XPbase/font/readme.txt b/AO2XPbase/font/readme.txt new file mode 100644 index 0000000..63030c5 --- /dev/null +++ b/AO2XPbase/font/readme.txt @@ -0,0 +1,31 @@ +Igiari by Caveras - based on the original main text pixel font used in +the Ace Attorney video game series for Game Boy Advance and Nintendo DS +(Capcom, 2001-2011). + +The font file in this archive was created by Caveras using FontStruct - +the free, online font-building tool. This font has a homepage where this +archive and other versions may be found: +http://fontstruct.com/fontstructors/caveras + +It is also distributed over Caveras' website: http://www.caveras.net + +Try FontStruct at http://fontstruct.com - It’s easy and it’s fun. + +NOTE FOR FLASH USERS: FontStruct fonts (FontStructions) are optimized for +Flash. The font in this archive is a pixel font and best displayed at a +font-size of 8 and multiples of this number. + +FontStruct is sponsored by FontShop. Visit them at http://fontshop.com. +FontShop is the original independent font retailer. We’ve been around since +the dawn of digital type. Whether you need the right font or need to create +the right font from scratch, let our 23 years of experience work for you. + +FontStruct is copyright © 2013-2014 Rob Meek + +LEGAL NOTICE: +In using this font you must comply with the licensing terms described in the +file “license.txt” included with this archive. If you redistribute the font +file in this archive, it must be accompanied by all the other files from this +archive, including this one. + +Copyright © 2014 Caveras / Cliff Modes. \ No newline at end of file diff --git a/AO2XPbase/themes/AceAttorney2x/Ace_Name_Regular.ttf b/AO2XPbase/themes/AceAttorney2x/Ace_Name_Regular.ttf new file mode 100644 index 0000000..d5c6e88 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/Ace_Name_Regular.ttf differ diff --git a/AO2XPbase/themes/AceAttorney2x/chat.png b/AO2XPbase/themes/AceAttorney2x/chat.png new file mode 100644 index 0000000..b5aea1e Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chat.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/chat_arrow.gif b/AO2XPbase/themes/AceAttorney2x/chat_arrow.gif new file mode 100644 index 0000000..d247f77 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chat_arrow.gif differ diff --git a/AO2XPbase/themes/AceAttorney2x/chat_arrow.webp b/AO2XPbase/themes/AceAttorney2x/chat_arrow.webp new file mode 100644 index 0000000..83ed810 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chat_arrow.webp differ diff --git a/AO2XPbase/themes/AceAttorney2x/chatbig.png b/AO2XPbase/themes/AceAttorney2x/chatbig.png new file mode 100644 index 0000000..8e8b156 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chatbig.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/chatblank.png b/AO2XPbase/themes/AceAttorney2x/chatblank.png new file mode 100644 index 0000000..8ed4928 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chatblank.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/chatmed.png b/AO2XPbase/themes/AceAttorney2x/chatmed.png new file mode 100644 index 0000000..72e6d66 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/chatmed.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/courtroom_stylesheets.css b/AO2XPbase/themes/AceAttorney2x/courtroom_stylesheets.css new file mode 100644 index 0000000..d506274 --- /dev/null +++ b/AO2XPbase/themes/AceAttorney2x/courtroom_stylesheets.css @@ -0,0 +1,86 @@ +QFrame { + color: white; + background-color: transparent; +} + +AOClockLabel { + border: 1px solid rgba(255, 255, 255, 135); + border-radius: 2px; + background-color: rgba(0, 0, 7, 135); + padding: 0px; +} + +QCheckBox { + color: white; + background-color: transparent; +} + +QComboBox { + border: 1px solid black; + border-radius: 3px; + background-color: darkgray; + color: black; +} + +QAbstractItemView { + border: 0px solid darkgray; + background-color: transparent; + color: black; + border-radius: 0px; + selection-background-color: darkgreen; +} + +QListView { + color: black; + background-color: white; + selection-background-color: darkgreen; +} + +QLineEdit { + color: white; + background-color: transparent; +} + +QScrollBar { + height: 12px; + width: 12px; + background-color: transparent; +} + +QScrollBar::add-page { + background: rgba(200, 255, 255, 24) +} + +QScrollBar::sub-page { + background: none +} + +AOButton { + background: darkgray; +} + +QSlider::handle { + background: darkgray; + border: 1px solid #5c5c5c; + border-radius: 3px; +} + + +QTextBrowser#ui_debug_log { + background-color: rgba(20, 20, 20, 255); +} + +QLineEdit#ui_ic_chat_name { + color: white; + background-color: darkgray; +} + +QLabel#ui_size_label { + color: lime; + background-color: black; +} + +AOEmotePreview { + background: rgb(0, 0, 0); + background: qlineargradient(spread:pad, x1:0 y1:0, x2:0 y2:1, stop:0 slategray, stop:1 darkslategray); +} \ No newline at end of file diff --git a/AO2XPbase/themes/AceAttorney2x/courtroombackground.png b/AO2XPbase/themes/AceAttorney2x/courtroombackground.png new file mode 100644 index 0000000..c08c6ef Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/courtroombackground.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/evidence_background.png b/AO2XPbase/themes/AceAttorney2x/evidence_background.png new file mode 100644 index 0000000..17872b6 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/evidence_background.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/evidence_background_private.png b/AO2XPbase/themes/AceAttorney2x/evidence_background_private.png new file mode 100644 index 0000000..57972d9 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/evidence_background_private.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/evidence_overlay.png b/AO2XPbase/themes/AceAttorney2x/evidence_overlay.png new file mode 100644 index 0000000..b89a401 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/evidence_overlay.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/evidence_overlay_private.png b/AO2XPbase/themes/AceAttorney2x/evidence_overlay_private.png new file mode 100644 index 0000000..42ce0b3 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/evidence_overlay_private.png differ diff --git a/AO2XPbase/themes/AceAttorney2x/igiari-cyrillic.ttf b/AO2XPbase/themes/AceAttorney2x/igiari-cyrillic.ttf new file mode 100644 index 0000000..a846a88 Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/igiari-cyrillic.ttf differ diff --git a/AO2XPbase/themes/AceAttorney2x/music_display.png b/AO2XPbase/themes/AceAttorney2x/music_display.png new file mode 100644 index 0000000..9b704db Binary files /dev/null and b/AO2XPbase/themes/AceAttorney2x/music_display.png differ diff --git a/audio.py b/audio.py index c3bcd50..1ce87e5 100644 --- a/audio.py +++ b/audio.py @@ -108,4 +108,7 @@ def sethandleattr(handle, attr, value): Set handle attribute """ if use_ctypes and type(value) == float: value = ctypes.c_float(value) - return dll.BASS_ChannelSetAttribute(handle, attr, value) \ No newline at end of file + return dll.BASS_ChannelSetAttribute(handle, attr, value) + +def getbasserror(): + return dll.BASS_ErrorGetCode() \ No newline at end of file diff --git a/bass_test.py b/bass_test.py new file mode 100644 index 0000000..3790027 --- /dev/null +++ b/bass_test.py @@ -0,0 +1,24 @@ +import __builtin__ +import audio as AUDIO +__builtin__.audio = AUDIO +del AUDIO +from pybass_constants import * + +audio.init() + +mus = "http://files.catbox.moe/nyp4xo.mp3" + +music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK) +print "Trying to play", mus + +if music: + audio.sethandleattr(music, BASS_ATTRIB_VOL, 1.0) + audio.playhandle(music, True) +else: + print "Couldn't play music. Error", audio.getbasserror() + +while (1): + pass + +audio.free() +sys.exit(0) \ No newline at end of file diff --git a/build.bat b/build.bat index 8cc67a4..e01bfbd 100644 --- a/build.bat +++ b/build.bat @@ -1,4 +1,5 @@ -pyinstaller AO2XP.spec -pyinstaller AO2XP_console.spec -pyinstaller install_update.spec +pyinstaller --debug=all AO2XP.spec +pyinstaller --debug=all AO2XP_console.spec +pyinstaller --debug=all install_update.spec move .\dist\* . +pause \ No newline at end of file diff --git a/game_version.py b/game_version.py index f872331..cbac2ac 100644 --- a/game_version.py +++ b/game_version.py @@ -1 +1 @@ -GAME_VERSION = "v1.6" \ No newline at end of file +GAME_VERSION = "2.6.0" \ No newline at end of file diff --git a/gameview.py b/gameview.py index 55388fa..f9945e4 100644 --- a/gameview.py +++ b/gameview.py @@ -62,6 +62,9 @@ C_CYAN = 8 DOWNLOAD_BLACKLIST = [] +VIEWPORT_W = 256*2 +VIEWPORT_H = 192*2 + def delay(msec): dieTime = QtCore.QTime.currentTime().addMSecs(msec) @@ -75,7 +78,12 @@ def encode_ao_str(text): def get_char_ini(char, section, value, default=""): tempini = ConfigParser() - tempini.read(AOpath + 'characters/' + char + '/char.ini') + with open(AOpath + 'characters/' + char + '/char.ini', 'r') as file: + for line in file: + try: + tempini.readfp(file) + except: + pass return ini.read_ini(tempini, section, value, default) def get_option(section, value, default=""): @@ -209,12 +217,13 @@ class AOCharMovie(QtGui.QLabel): def __init__(self, parent): QtGui.QLabel.__init__(self, parent) - self.resize(256, 192) + self.resize(VIEWPORT_W, VIEWPORT_H) self.time_mod = 62 self.play_once = True self.m_flipped = False self.m_movie = QtGui.QMovie() + self.setScaledContents(True) self.preanim_timer = QtCore.QTimer(self) self.preanim_timer.setSingleShot(True) @@ -542,7 +551,8 @@ class ZoomLines(QtGui.QLabel): def __init__(self, parent): super(ZoomLines, self).__init__(parent) - self.resize(256, 192) + self.resize(VIEWPORT_W, VIEWPORT_H) + self.setScaledContents(True) self.movie = QtGui.QMovie() self.movie.frameChanged.connect(self.frame_change) @@ -572,7 +582,8 @@ class WTCE_View(QtGui.QLabel): self.finalframe_timer = QtCore.QTimer() self.finalframe_timer.setSingleShot(False) self.finalframe_timer.timeout.connect(self.finished) - self.resize(256, 192) + self.resize(VIEWPORT_W, VIEWPORT_H) + self.setScaledContents(True) def frame_change(self, frame): if self.movie.state() != QtGui.QMovie.Running: @@ -636,6 +647,9 @@ class gui(QtGui.QWidget): charini = ConfigParser() chatmsg = '' charid = -1 + + wtcesfx = None + #ICchat = QtCore.pyqtSignal(str, str, str, str, str, str, int, int, int, int, int, int, int, int) #ICchat = QtCore.pyqtSignal(list) WTCEsignal = QtCore.pyqtSignal(str, int) @@ -667,9 +681,10 @@ class gui(QtGui.QWidget): self.background = 'default' self.viewport = QtGui.QWidget(self) - self.viewport.resize(256, 192) + self.viewport.resize(VIEWPORT_W, VIEWPORT_H) self.court = QtGui.QLabel(self.viewport) + self.court.resize(VIEWPORT_W, VIEWPORT_H) self.zoom = ZoomLines(self.viewport) self.char = AOCharMovie(self.viewport) @@ -678,23 +693,33 @@ class gui(QtGui.QWidget): self.sidechar.hide() self.bench = QtGui.QLabel(self.viewport) + self.bench.resize(VIEWPORT_W, VIEWPORT_H) bench = QtGui.QPixmap(AOpath + 'background/default/defensedesk.png') self.court.setPixmap(QtGui.QPixmap(AOpath + 'background/default/defenseempty.png')) self.bench.setPixmap(bench) self.effectview = AOMovie(self.viewport) + + font_db = QtGui.QFontDatabase() + font_db.addApplicationFont(AO2XPpath + 'font/Igiari.ttf') + font_db.addApplicationFont(AO2XPpath + 'font/Ace_Name_Regular.ttf') + name_font = QtGui.QFont("Ace Name") + name_font.setPointSize(12) + ao2text_font = QtGui.QFont("Igiari") + ao2text_font.setPointSize(24) self.chatbox = QtGui.QLabel(self.viewport) - chatbox = QtGui.QPixmap(AO2XPpath + 'themes/default/chatmed.png') + chatbox = QtGui.QPixmap(AO2XPpath + 'themes/AceAttorney2x/chatbig.png') + #chatbox = QtGui.QPixmap(AO2XPpath + 'themes/default/chatmed.png') self.chatboxheight = chatbox.size().height() self.chatbox.setPixmap(chatbox) - self.chatbox.move(0, 192 - self.chatboxheight) + self.chatbox.move(0, VIEWPORT_H - self.chatboxheight) self.text = QtGui.QLabel(self.chatbox) self.text.setWordWrap(True) - self.text.resize(250, 96) + self.text.resize(VIEWPORT_W, 96) self.text.move(6, 20) - self.text.setStyleSheet('color: white') + self.text.setStyleSheet('color: white;') self.text.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.ao2text = QtGui.QTextEdit(self.chatbox) @@ -702,19 +727,24 @@ class gui(QtGui.QWidget): self.ao2text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.ao2text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.ao2text.setReadOnly(True) - self.ao2text.setGeometry(2, 16, 240+10, 96) + self.ao2text.setGeometry(16, 32, VIEWPORT_W - 16, 112) self.ao2text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) - self.ao2text.setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white") + self.ao2text.setStyleSheet("background-color: rgba(0, 0, 0, 0); color: white;") + self.ao2text.setFont(ao2text_font) self.name = QtGui.QLabel(self.chatbox) self.name.setStyleSheet('color: white') - self.name.move(5, 0) - self.name.resize(248, self.name.sizeHint().height()) + self.name.move(16, 0) + self.name.resize(248, 32) + #self.name.resize(248, self.name.sizeHint().height()) + self.name.setFont(name_font) + self.wtceview = WTCE_View(self) self.WTCEsignal.connect(self.wtceview.showWTCE) self.objectionview = AOMovie(self.viewport) + self.objectionview.resize(VIEWPORT_W, VIEWPORT_H) + self.objectionview.setScaledContents(True) self.objectionview.done.connect(self.objection_done) self.whiteflashlab = QtGui.QLabel(self.viewport) @@ -859,76 +889,77 @@ class gui(QtGui.QWidget): self.gametabs.addTab(self.gametab_misc, 'Misc') self.icchatinput = QtGui.QLineEdit(self) - self.icchatinput.setGeometry(0, 192, 256, 23) + self.icchatinput.setGeometry(0, VIEWPORT_H, VIEWPORT_W, 23) self.icchatinput.returnPressed.connect(self.onICreturn) self.icchatinput.setPlaceholderText('Game chat') self.emotedropdown = QtGui.QComboBox(self) - self.emotedropdown.setGeometry(192, 344, 128, 20) + self.emotedropdown.setGeometry(164 - 28, 344 + 66 + 4, 72, 20) self.emotedropdown.currentIndexChanged.connect(partial(self.changeEmote, True)) self.colordropdown = QtGui.QComboBox(self) - self.colordropdown.setGeometry(192, 376, 72, 20) + self.colordropdown.setGeometry(self.emotedropdown.x(), 376 + 64, 72, 20) self.colordropdown.currentIndexChanged.connect(self.setChatColor) self.posdropdown = QtGui.QComboBox(self) self.posdropdown.addItems(["def", "pro", "wit", "hld", "hlp", "jud"]) - self.posdropdown.setGeometry(self.emotedropdown.x() + self.emotedropdown.size().width() + 8, 344, 64, 20) + self.posdropdown.setGeometry(self.emotedropdown.x() + self.emotedropdown.size().width() + 4, self.emotedropdown.y(), 72, 20) self.posdropdown.currentIndexChanged.connect(self.setPosition) self.flipbutton = QtGui.QCheckBox(self) self.flipbutton.stateChanged.connect(self.changeFlipCheck) - self.flipbutton.setText('Mirror emote') + self.flipbutton.setText('Mirror') self.flipbutton.resize(self.flipbutton.sizeHint()) - self.flipbutton.move(272, 240) + self.flipbutton.move(self.posdropdown.x() + self.posdropdown.width() + 4, self.colordropdown.y() - 5) self.sfxbutton = QtGui.QCheckBox(self) self.sfxbutton.setChecked(True) self.sfxbutton.stateChanged.connect(self.changeSfxCheck) self.sfxbutton.setText('Play pre-animation') self.sfxbutton.resize(self.sfxbutton.sizeHint()) - self.sfxbutton.move(272, 272-12) + self.sfxbutton.move(self.flipbutton.x(), self.flipbutton.y() + 14) self.nointerruptbtn = QtGui.QCheckBox(self) self.nointerruptbtn.setChecked(False) self.nointerruptbtn.setText('No Interrupt') self.nointerruptbtn.resize(self.nointerruptbtn.sizeHint()) - self.nointerruptbtn.move(272, 272+8) + self.nointerruptbtn.move(self.flipbutton.x() + 140, self.flipbutton.y()) # AO 2.8 self.additivebtn = QtGui.QCheckBox(self) self.additivebtn.setChecked(False) self.additivebtn.setText('Additive text') self.additivebtn.resize(self.additivebtn.sizeHint()) - self.additivebtn.move(272+60, 272+28) + self.additivebtn.move(self.nointerruptbtn.x(), self.sfxbutton.y()) self.additivebtn.clicked.connect(self.onAdditiveCheck) self.deskbtn = QtGui.QCheckBox(self) self.deskbtn.setChecked(True) self.deskbtn.setText('Desk') self.deskbtn.resize(self.nointerruptbtn.sizeHint()) - self.deskbtn.move(self.flipbutton.x()+96, self.flipbutton.y()) + self.deskbtn.move(self.flipbutton.x()+70, self.flipbutton.y()) self.effectdropdown = QtGui.QComboBox(self) - self.effectdropdown.setGeometry(272+60, 272+28+18, 88, 20) - - self.changechar = QtGui.QPushButton(self) - self.changechar.setText('Switch character') - self.changechar.setGeometry(10, 344, 121, 23) - self.changechar.clicked.connect(self.onClick_changeChar) + self.effectdropdown.setGeometry(self.posdropdown.x(), self.colordropdown.y(), 72, 20) + self.callmodbtn = QtGui.QPushButton(self) self.callmodbtn.setText('Call mod') - self.callmodbtn.setGeometry(10, 376, 71, 23) + self.callmodbtn.setGeometry(10, 376 + 62, 60, 23) self.callmodbtn.clicked.connect(self.onClick_callMod) self.settingsbtn = QtGui.QPushButton("Settings", self) - self.settingsbtn.setGeometry(self.callmodbtn.x()+self.callmodbtn.size().width()+8, 376, self.settingsbtn.sizeHint().width(), 23) + self.settingsbtn.setGeometry(self.callmodbtn.x()+self.callmodbtn.size().width(), 376 + 62, self.callmodbtn.width(), 23) self.settingsbtn.clicked.connect(self.gamewindow.showSettings) + + self.changechar = QtGui.QPushButton(self) + self.changechar.setText('Switch character') + self.changechar.setGeometry(10, 344 + 66 + 4, self.callmodbtn.size().width() + self.settingsbtn.size().width(), 23) + self.changechar.clicked.connect(self.onClick_changeChar) - spacing = 9 + spacing = 1 x_mod_count = y_mod_count = 0 - left, top = (10, 218) - width, height = (236, 98) + left, top = (10 + 516, 218+190-24) + width, height = (288, 98) columns = (width - 40) / (spacing + 40) + 1 rows = (height - 40) / (spacing + 40) + 1 self.max_emotes_on_page = columns * rows @@ -944,31 +975,33 @@ class gui(QtGui.QWidget): self.emotebuttons[i].show() self.current_emote_page = 0 - self.prevemotepage = BackEmoteButton(self, 0, 253) + self.prevemotepage = BackEmoteButton(self, 520, 253+190-28) self.prevemotepage.hide() - self.nextemotepage = NextEmoteButton(self, 236, 253) + self.nextemotepage = NextEmoteButton(self, 282 + 516, 253+190-28) self.nextemotepage.show() - self.realizationbtn = buttons.AOToggleButton(self, 265, 192, "realization") + self.realizationbtn = buttons.AOToggleButton(self, 265 + 164, 192 + 304, "realization") self.realizationbtn.clicked.connect(self.onRealizationButton) self.realizationsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-realization.wav', 0, 0, 0) - self.shakebtn = buttons.AOToggleButton(self, 265+42, 192, "screenshake") # AO 2.8 - self.customobject = buttons.CustomObjection(self, 250, 312) - self.holditbtn = buttons.Objections(self, 10, 312, 1) - self.objectbtn = buttons.Objections(self, 90, 312, 2) - self.takethatbtn = buttons.Objections(self, 170, 312, 3) + self.shakebtn = buttons.AOToggleButton(self, 265+42 + 164, 192 + 304, "screenshake") # AO 2.8 + self.customobject = buttons.CustomObjection(self, 250 + 516 - 30, 312 + 40) + self.takethatbtn = buttons.Objections(self, 170+ 516 - 20, 312 + 40, 3) + self.objectbtn = buttons.Objections(self, 90+ 516 - 10, 312 + 40, 2) + self.holditbtn = buttons.Objections(self, 10+ 516, 312 + 40, 1) self.objectsnd = None self.defensebar = buttons.PenaltyBars(self, 1) self.prosecutionbar = buttons.PenaltyBars(self, 2) - self.defensebar.moveBar(265, 164) - self.prosecutionbar.moveBar(265, 178) + self.defensebar.moveBar(265 + 164, 164 + 304) + self.prosecutionbar.moveBar(265 + 164, 178 + 304) self.defensebar.minusClicked.connect(self.penaltyBarMinus) self.defensebar.plusClicked.connect(self.penaltyBarPlus) self.prosecutionbar.minusClicked.connect(self.penaltyBarMinus) self.prosecutionbar.plusClicked.connect(self.penaltyBarPlus) - self.wtcebtn_1 = buttons.WTCEbuttons(self, 256, 0, 0) - self.wtcebtn_2 = buttons.WTCEbuttons(self, 256 + self.wtcebtn_1.size().width(), 0, 1) - self.notguiltybtn = buttons.WTCEbuttons(self, 256, self.wtcebtn_1.size().height(), 2, 0) - self.guiltybtn = buttons.WTCEbuttons(self, 256 + self.notguiltybtn.size().width(), self.wtcebtn_2.size().height(), 2, 1) + + self.wtcebtn_1 = buttons.WTCEbuttons(self, 429, 544, 0) + self.wtcebtn_2 = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.wtcebtn_1.y() + self.wtcebtn_1.size().height(), 1) + self.notguiltybtn = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.wtcebtn_2.y() + self.wtcebtn_2.size().height(), 2, 0) + self.guiltybtn = buttons.WTCEbuttons(self, self.wtcebtn_1.x(), self.notguiltybtn.y() + self.notguiltybtn.size().height(), 2, 1) + self.wtcebtn_1.clicked.connect(self.WTCEbuttonPressed) self.wtcebtn_2.clicked.connect(self.WTCEbuttonPressed) self.notguiltybtn.clicked.connect(self.WTCEbuttonPressed) @@ -985,7 +1018,7 @@ class gui(QtGui.QWidget): self.showname = "" self.shownameedit = QtGui.QLineEdit(self) self.shownameedit.textChanged.connect(self.onChangeShowname) - self.shownameedit.setGeometry(self.colordropdown.x()+self.colordropdown.width()+8, self.colordropdown.y(), 144, 20) + self.shownameedit.setGeometry(self.posdropdown.x() + self.posdropdown.width() + 4, self.posdropdown.y(), 168 + 56, 20) self.shownameedit.setPlaceholderText("Showname") self.musicslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) @@ -1638,8 +1671,8 @@ class gui(QtGui.QWidget): bgimg = QtGui.QImage(AOpath + 'background/' + bg + '/' + bgfile[1] + '.png') if not bgimg.isNull(): - if bgimg.size().width() != 256 or bgimg.size().height() != 192: - setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(256, 192, transformMode=QtCore.Qt.SmoothTransformation))) + if bgimg.size().width() != VIEWPORT_W or bgimg.size().height() != VIEWPORT_H: + setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(VIEWPORT_W, VIEWPORT_H, transformMode=QtCore.Qt.SmoothTransformation))) else: setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg)) else: @@ -1783,12 +1816,12 @@ class gui(QtGui.QWidget): if side == 'def': self.court.setPixmap(self.side_def) self.bench.setPixmap(self.bench_def) - self.bench.move(0, 192 - self.bench_def.size().height()) + self.bench.move(0, VIEWPORT_H - self.bench_def.size().height()) self.presentedevi.move(170, 16) elif side == 'pro': self.court.setPixmap(self.side_pro) self.bench.setPixmap(self.bench_pro) - self.bench.move(256 - self.bench_pro.size().width(), 192 - self.bench_pro.size().height()) + self.bench.move(VIEWPORT_W - self.bench_pro.size().width(), VIEWPORT_H - self.bench_pro.size().height()) self.presentedevi.move(16, 16) elif side == 'wit': self.court.setPixmap(self.side_wit) @@ -2368,13 +2401,14 @@ class gui(QtGui.QWidget): audio.freehandle(self.music) if exists(AOpath + 'sounds/music/' + mus): - self.music = audio.loadhandle(False, AOpath + 'sounds/music/' + mus, 0, 0, 0) + self.music = audio.loadhandle(False, AOpath + 'sounds/music/' + mus, 0, 0, BASS_SAMPLE_LOOP) audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) audio.playhandle(self.music, True) elif ini.read_ini_bool("AO2XP.ini", "General", "download music", True): if mus.lower().startswith("http"): - self.music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK) + self.music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP) + print "Trying to play", mus.lower() else: for bucket in buckets: if not bucket: continue @@ -2385,6 +2419,8 @@ class gui(QtGui.QWidget): if self.music: audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) audio.playhandle(self.music, True) + else: + print "Couldn't play music. Error", audio.getbasserror() def stopMusic(self): if self.music: @@ -2437,7 +2473,7 @@ class gui(QtGui.QWidget): self.colordropdown.clear() self.colordropdown.addItems(['white', 'green', 'red', 'orange', 'blue']) if "yellowtext" in features: - self.colordropdown.addItems(['yellow', 'gay pride', 'pink', 'cyan']) + self.colordropdown.addItems(['yellow', 'rainbow', 'pink', 'cyan']) self.colordropdown.setCurrentIndex(self.mychatcolor) for hp in hplist: @@ -2825,7 +2861,8 @@ class TCP_Thread(QtCore.QThread): elif header == 'RT': testimony = network[1] wtcefile = AOpath+"sounds/general/sfx-testimony2" - audio.freehandle(self.parent.wtcesfx) + if self.parent.wtcesfx: + audio.freehandle(self.parent.wtcesfx) if testimony == 'judgeruling': variant = int(network[2]) diff --git a/gameview_scaled.py b/gameview_scaled.py new file mode 100644 index 0000000..a564187 --- /dev/null +++ b/gameview_scaled.py @@ -0,0 +1,2882 @@ +import thread, time, os, buttons, urllib, charselect, ini, random +from os.path import exists +from ConfigParser import ConfigParser + +from pybass_constants import * +from PyQt4 import QtGui, QtCore +from functools import partial + +import AOsocket +import images + +AOpath = "base/" +AO2XPpath = "AO2XPbase/" +#AOpath = 'I:/aovanilla1.7.5/client/base/' + +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 + +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_RAINBOW = 6 +C_PINK = 7 +C_CYAN = 8 + +DOWNLOAD_BLACKLIST = [] + +def delay(msec): + dieTime = QtCore.QTime.currentTime().addMSecs(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() + with open(AOpath + 'characters/' + char + '/char.ini', 'r') as file: + for line in file: + try: + tempini.readfp(file) + except: + pass + return ini.read_ini(tempini, section, value, default) + +def get_option(section, value, default=""): + tempini = ConfigParser() + tempini.read("AO2XP.ini") + return ini.read_ini(tempini, section, value, default) + +def get_img_suffix(path): + if exists(path): return path + if exists(path+".webp"): return path+".webp" + if exists(path+".apng"): return path+".apng" + if exists(path+".gif"): return path+".gif" + return path+".png" + +def get_text_color(textcolor): + if textcolor == 0 or textcolor == 6: + return QtGui.QColor(255, 255, 255) + elif textcolor == 1: + return QtGui.QColor(0, 255, 0) + elif textcolor == 2: # OH FUCK MOD + return QtGui.QColor(255, 0, 0) + elif textcolor == 3: + return QtGui.QColor(255, 165, 0) + elif textcolor == 4: + return QtGui.QColor(45, 150, 255) + elif textcolor == 5: + return QtGui.QColor(255, 255, 0) + elif textcolor == 7: + return QtGui.QColor(255, 192, 203) + elif textcolor == 8: + return QtGui.QColor(0, 255, 255) + elif textcolor == "_inline_grey": + return QtGui.QColor(187, 187, 187) + + return QtGui.QColor(0, 0, 0) + +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 + +def download_thread(link, savepath): + global DOWNLOAD_BLACKLIST + if link in DOWNLOAD_BLACKLIST: + return + + for bucket in buckets: + if not bucket: continue + i = buckets.index(bucket) + + print "download missing: %s" % link + fp = urllib.urlopen(bucket+link) + if fp.getcode() == 200: + if not os.path.exists(savepath[:-1]): + os.makedirs(savepath[:-1]) + + with open(savepath, "wb") as f: + f.write(fp.read()) + print "successfully downloaded:", link + return + + DOWNLOAD_BLACKLIST.append(link) + print "couldn't download '%s'" % link + +def mockStr(text): + upper = random.choice([True, False]) + l = list(text) + for i in range(len(text)): + if text[i] == " ": + continue + + l[i] = l[i].upper() if upper else l[i].lower() + upper = not upper + return "".join(l) + +class ChatLogs(QtGui.QTextEdit): + def __init__(self, parent, logtype, logfile=None): + QtGui.QTextEdit.__init__(self, parent) + self.type = logtype + self.savelog = ini.read_ini_bool("AO2XP.ini", "General", "save logs") + self.combinelog = ini.read_ini_bool("AO2XP.ini", "General", "combined logs") + if not exists("chatlogs"): + os.mkdir("chatlogs") + + if self.savelog: + currtime = time.localtime() + if self.combinelog: + if self.type == 0: + self.logfile = logfile + else: + self.logfile = open("chatlogs/%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w") + else: + if self.type == 0: + self.logfile = open("chatlogs/IC_%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w") + else: + self.logfile = open("chatlogs/OOC_%d%.2d%.2d_on_%.2d.%.2d.%.2d.txt" % (currtime[0], currtime[1], currtime[2], currtime[3], currtime[4], currtime[5]), "w") + else: + self.logfile = None + + def __del__(self): + if self.savelog: + self.logfile.close() + + def append(self, text): + super(ChatLogs, self).append(text) + if self.savelog: + if isinstance(text, str) or isinstance(text, unicode): + if self.combinelog and not "Log started" in text: + if self.type == 0: + self.logfile.write("[IC] "+text.encode("utf-8")+"\n") + else: + self.logfile.write("[OOC] "+text.encode("utf-8")+"\n") + else: + self.logfile.write(text.encode("utf-8")+"\n") + else: + if self.combinelog and not "Log started" in text: + if self.type == 0: + self.logfile.write("[IC] "+text.toUtf8()+"\n") + else: + self.logfile.write("[OOC] "+text.toUtf8()+"\n") + else: + self.logfile.write(text.toUtf8()+"\n") + +class AOCharMovie(QtGui.QLabel): + done = QtCore.pyqtSignal() + use_pillow = 0 + pillow_frames = [] + pillow_frame = 0 + pillow_speed = 0 + xx = 0 # for restoring from screenshake + yy = 0 # for restoring from screenshake + + def __init__(self, parent): + QtGui.QLabel.__init__(self, parent) + + self.resize(256*2, 192*2) + self.time_mod = 62 + self.play_once = True + self.m_flipped = False + + self.m_movie = QtGui.QMovie() + + self.preanim_timer = QtCore.QTimer(self) + self.preanim_timer.setSingleShot(True) + self.pillow_timer = QtCore.QTimer(self) + self.pillow_timer.setSingleShot(True) + + self.preanim_timer.timeout.connect(self.timer_done) + self.pillow_timer.timeout.connect(self.pillow_frame_change) + self.m_movie.frameChanged.connect(self.frame_change) + + def move(self, x, y, screenShaking=False): + if not screenShaking: + self.xx = x + self.yy = y + super(AOCharMovie, self).move(x, y) + + def set_flipped(self, flip): + self.m_flipped = flip + + def play(self, p_char, p_emote, emote_prefix): + if p_emote[0] == "/" or p_emote[0] == "/": + p_emote = p_emote[1:] + elif "../../characters" in p_emote: + print p_emote + a = p_emote.split("/") + p_char = a[3] + emote = a[4] + emote_prefix = "" + p_emote = emote + + self.pillow_frames = [] + self.pillow_frame = 0 + + original_path = AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".gif" + alt_path = AOpath+"characters/"+p_char+"/"+p_emote+".png" + apng_path = AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".apng" + webp_path = AOpath+"characters/"+p_char+"/"+emote_prefix+p_emote+".webp" + placeholder_path = AO2XPpath+"themes/default/placeholder.gif" + gif_path = "" + + if exists(apng_path): + gif_path = apng_path + self.use_pillow = 1 + else: + if ini.read_ini_bool("AO2XP.ini", "General", "download characters"): + url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".apng" + url = url.replace(" ", "%20") + thread.start_new_thread(download_thread, (url, apng_path)) + + if exists(webp_path): + gif_path = webp_path + self.use_pillow = 2 + else: + if ini.read_ini_bool("AO2XP.ini", "General", "download characters"): + url = "base/characters/"+p_char.lower()+"/"+p_emote.lower()+".webp" + url = url.replace(" ", "%20") + thread.start_new_thread(download_thread, (url, webp_path)) + + if exists(original_path): + gif_path = original_path + self.use_pillow = 0 + else: + if ini.read_ini_bool("AO2XP.ini", "General", "download characters"): + url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".gif" + url = url.replace(" ", "%20") + thread.start_new_thread(download_thread, (url, original_path)) + + if exists(alt_path): + gif_path = alt_path + self.use_pillow = 0 + else: + if ini.read_ini_bool("AO2XP.ini", "General", "download characters"): + url = "base/characters/"+p_char.lower()+"/"+emote_prefix+p_emote.lower()+".png" + url = url.replace(" ", "%20") + thread.start_new_thread(download_thread, (url, alt_path)) + + if exists(placeholder_path): + gif_path = placeholder_path + else: + gif_path = "" + self.use_pillow = 0 + + if not self.use_pillow: + self.m_movie.stop() + self.m_movie.setFileName(gif_path) + self.m_movie.start() + + elif self.use_pillow == 1: # apng + self.pillow_frames = images.load_apng(apng_path) + if len(self.pillow_frames) > 1: self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed)) + self.set_pillow_frame() + + elif self.use_pillow == 2: # webp + self.pillow_frames = images.load_webp(webp_path) + if len(self.pillow_frames) > 1: self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed)) + self.set_pillow_frame() + + self.show() + + def play_pre(self, p_char, p_emote, duration): + gif_path = AOpath+"characters/"+p_char+"/"+p_emote+".gif" + apng_path = AOpath+"characters/"+p_char+"/"+p_emote+".apng" + webp_path = AOpath+"characters/"+p_char+"/"+p_emote+".webp" + + full_duration = duration * self.time_mod + real_duration = 0 + + self.play_once = False + self.m_movie.stop() + self.clear() + + if exists(apng_path): + real_duration = images.get_apng_duration(apng_path) + + elif exists(webp_path): + real_duration = images.get_webp_duration(webp_path) + + elif exists(gif_path): + self.m_movie.setFileName(gif_path) + self.m_movie.jumpToFrame(0) + for n_frame in range(self.m_movie.frameCount()): + real_duration += self.m_movie.nextFrameDelay() + self.m_movie.jumpToFrame(n_frame + 1) + + percentage_modifier = 100.0 + + if real_duration != 0 and duration != 0: + modifier = full_duration / float(real_duration) + percentage_modifier = 100 / modifier + + if percentage_modifier > 100.0 or percentage_modifier < 0.0: + percentage_modifier = 100.0 + + self.pillow_fullduration = full_duration + if full_duration == 0 or full_duration >= real_duration: + self.play_once = True + else: + self.play_once = False + if full_duration >= 0: + self.preanim_timer.start(full_duration) + + self.m_movie.setSpeed(int(percentage_modifier)) + self.pillow_speed = percentage_modifier / 100. + self.play(p_char, p_emote, "") + + def play_talking(self, p_char, p_emote): + gif_path = AOpath + 'characters/' + p_char + '/(b)' + p_emote + '.gif' + + self.m_movie.stop() + self.clear() + self.m_movie.setFileName(gif_path) + self.m_movie.jumpToFrame(0) + + self.play_once = False + self.m_movie.setSpeed(100) + self.pillow_speed = 1 + self.play(p_char, p_emote, '(b)') + + def play_idle(self, p_char, p_emote): + gif_path = AOpath + 'characters/' + p_char + '/(a)' + p_emote + '.gif' + + self.m_movie.stop() + self.clear() + self.m_movie.setFileName(gif_path) + self.m_movie.jumpToFrame(0) + + self.play_once = False + self.m_movie.setSpeed(100) + self.pillow_speed = 1 + self.play(p_char, p_emote, '(a)') + + def stop(self): + self.m_movie.stop() + self.preanim_timer.stop() + self.hide() + + @QtCore.pyqtSlot(int) + def frame_change(self, n_frame): + f_img = self.m_movie.currentImage().mirrored(self.m_flipped, False) + if f_img.size().width() != 256 or f_img.size().height() != 192: + f_img = f_img.scaled(256*2, 192*2, transformMode=QtCore.Qt.SmoothTransformation) + + f_pixmap = QtGui.QPixmap.fromImage(f_img) + self.setPixmap(f_pixmap) + + if self.m_movie.frameCount() - 1 == n_frame and self.play_once: + self.preanim_timer.start(self.m_movie.nextFrameDelay()) + + @QtCore.pyqtSlot() + def pillow_frame_change(self): + if not self.pillow_frames: return + + if len(self.pillow_frames)-1 == self.pillow_frame: + if self.play_once: + self.preanim_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + elif len(self.pillow_frames) > 1: + self.pillow_frame = 0 + self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + else: + self.pillow_frame += 1 + self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + + self.set_pillow_frame() + + def set_pillow_frame(self): + f_img = self.pillow_frames[self.pillow_frame][0].mirrored(self.m_flipped, False) + if f_img.size().width() != 256 or f_img.size().height() != 192: + f_img = f_img.scaled(256*2, 192*2, transformMode=QtCore.Qt.SmoothTransformation) + + f_pixmap = QtGui.QPixmap.fromImage(f_img) + self.setPixmap(f_pixmap) + + @QtCore.pyqtSlot() + def timer_done(self): + self.done.emit() + +class AOMovie(QtGui.QLabel): + play_once = True + done = QtCore.pyqtSignal() + use_pillow = 0 + pillow_frames = [] + pillow_frame = 0 + pillow_speed = 1 + xx = 0 # for restoring from screenshake + yy = 0 # for restoring from screenshake + + def __init__(self, parent): + QtGui.QLabel.__init__(self, parent) + self.m_movie = QtGui.QMovie() + self.setMovie(self.m_movie) + self.m_movie.frameChanged.connect(self.frame_change) + + self.pillow_timer = QtCore.QTimer(self) + self.pillow_timer.setSingleShot(True) + self.pillow_timer.timeout.connect(self.pillow_frame_change) + + def move(self, x, y): + self.xx = x + self.yy = y + super(AOMovie, self).move(x, y) + + def set_play_once(self, once): + self.play_once = once + + def play(self, p_image, p_char=""): + self.stop() + + gif_path = p_image + pillow_modes = {".gif": 0, ".apng": 1, ".webp": 2} + + if not exists(gif_path): + pathlist = [ + get_img_suffix(AO2XPpath+"themes/default/"+p_image+"_bubble"), + get_img_suffix(AOpath+"characters/"+p_char+"/"+p_image), + get_img_suffix(AOpath+"misc/default/"+p_image), + get_img_suffix(AO2XPpath+"themes/default/"+p_image), + AO2XPpath+"themes/default/placeholder.gif" + ] + + for f in pathlist: + if exists(f): + gif_path = f + break + + self.use_pillow = pillow_modes[os.path.splitext(gif_path)[1]] + if not self.use_pillow: + self.m_movie.setFileName(gif_path) + self.m_movie.start() + elif self.use_pillow == 1: # apng + self.pillow_frames = images.load_apng(gif_path) + if len(self.pillow_frames) > 1: self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed)) + self.set_pillow_frame() + elif self.use_pillow == 2: # webp + self.pillow_loops = 0 + self.pillow_frames, self.webp_loops = images.load_webp(gif_path) + if len(self.pillow_frames) > 1: self.pillow_timer.start(int(self.pillow_frames[0][1] * self.pillow_speed)) + self.set_pillow_frame() + + self.show() + + def stop(self): + self.pillow_frames = [] + self.pillow_frame = 0 + self.pillow_timer.stop() + self.m_movie.stop() + self.hide() + + @QtCore.pyqtSlot(int) + def frame_change(self, n_frame): + if n_frame == self.m_movie.frameCount() - 1 and self.play_once: + delay(self.m_movie.nextFrameDelay()) + self.stop() + self.done.emit() + + @QtCore.pyqtSlot() + def pillow_frame_change(self): + if not self.pillow_frames: return + + if len(self.pillow_frames)-1 == self.pillow_frame: + if self.play_once or (self.use_pillow == 2 and self.pillow_loops+1 == self.webp_loops): + delay(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + self.stop() + self.done.emit() + elif len(self.pillow_frames) > 1: # loop + self.pillow_loops += 1 + self.pillow_frame = 0 + self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + elif len(self.pillow_frames) > 1: + self.pillow_frame += 1 + self.pillow_timer.start(int(self.pillow_frames[self.pillow_frame][1] * self.pillow_speed)) + + self.set_pillow_frame() + + def set_pillow_frame(self): + if not self.pillow_frames: return + + f_img = self.pillow_frames[self.pillow_frame][0] + if f_img.size().width() != 256 or f_img.size().height() != 192: + f_img = f_img.scaled(256*2, 192*2, transformMode=QtCore.Qt.SmoothTransformation) + + f_pixmap = QtGui.QPixmap.fromImage(f_img) + self.setPixmap(f_pixmap) + +class ZoomLines(QtGui.QLabel): + + def __init__(self, parent): + super(ZoomLines, self).__init__(parent) + self.resize(256*2, 192*2) + self.movie = QtGui.QMovie() + self.movie.frameChanged.connect(self.frame_change) + + def frame_change(self): + img = self.movie.currentImage() + self.setPixmap(QtGui.QPixmap.fromImage(img)) + + def setZoom(self, on, dir=0): + self.movie.stop() + if not on: + self.hide() + return + self.show() + if dir == 0: + self.movie.setFileName(AO2XPpath + 'themes/default/defense_speedlines.gif') + else: + self.movie.setFileName(AO2XPpath + 'themes/default/prosecution_speedlines.gif') + self.movie.start() + + +class WTCE_View(QtGui.QLabel): + + def __init__(self, parent): + super(WTCE_View, self).__init__(parent) + self.movie = QtGui.QMovie() + self.movie.frameChanged.connect(self.frame_change) + self.finalframe_timer = QtCore.QTimer() + self.finalframe_timer.setSingleShot(False) + self.finalframe_timer.timeout.connect(self.finished) + self.resize(256*2, 192*2) + + def frame_change(self, frame): + if self.movie.state() != QtGui.QMovie.Running: + return + img = self.movie.currentImage() + self.setPixmap(QtGui.QPixmap.fromImage(img)) + if self.movie.currentFrameNumber() == self.movie.frameCount() - 1: + self.finalframe_timer.start(self.movie.nextFrameDelay()) + + def finished(self): + self.finalframe_timer.stop() + self.movie.stop() + self.hide() + + def showWTCE(self, wtce, variant=0): + self.finished() + 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: + self.movie.setFileName(AO2XPpath + 'themes/default/notguilty.gif') + elif variant == 1: + self.movie.setFileName(AO2XPpath + 'themes/default/guilty.gif') + else: + return + self.show() + self.movie.start() + +class gui(QtGui.QWidget): + gamewindow = None + sound = None + music = None + next_character_is_not_special = False + message_is_centered = False + current_display_speed = 3 + message_display_speed = (30, 40, 50, 60, 75, 100, 120) + entire_message_is_blue = False + inline_color_stack = [] #"colour" is for EU nobos + inline_blue_depth = 0 + other_charid = -1 + offset_with_pair = 0 + tick_pos = 0 + blip_pos = 0 + blip_rate = 1 + time_mod = 40 + blip = "male" + blipsnd = None + chatmessage_size = 31 + m_chatmessage = [] + blank_blip = False + chatmessage_is_empty = False + is_additive = False + additive_char = -1 + anim_state = 3 + text_state = 2 + objection_state = 0 + text_color = 0 + + charini = ConfigParser() + chatmsg = '' + charid = -1 + + wtcesfx = None + + #ICchat = QtCore.pyqtSignal(str, str, str, str, str, str, int, int, int, int, int, int, int, int) + #ICchat = QtCore.pyqtSignal(list) + WTCEsignal = QtCore.pyqtSignal(str, int) + healthbars = QtCore.pyqtSignal(int, int) + gotPing = QtCore.pyqtSignal(int) + + def __init__(self, parent=None): + super(gui, self).__init__(parent) + self.gamewindow = parent + + self.gotPing.connect(self.setPing) + + for i in range(self.chatmessage_size): + self.m_chatmessage.append("") + + self.chat_tick_timer = QtCore.QTimer(self) + self.chat_tick_timer.timeout.connect(self.chat_tick) + + self.sfx_delay_timer = QtCore.QTimer(self) + self.sfx_delay_timer.setSingleShot(True) + self.sfx_delay_timer.timeout.connect(self.play_sfx) + + self.modcall = None + + self.healthbars.connect(self.netmsg_hp) + self.disconnectnow = False + self.swapping = False + self.iniswapindex = 0 + self.background = 'default' + + self.viewport = QtGui.QWidget(self) + self.viewport.resize(256*2, 192*2) + + self.court = QtGui.QLabel(self.viewport) + self.zoom = ZoomLines(self.viewport) + + self.char = AOCharMovie(self.viewport) + self.char.done.connect(self.preanim_done) + self.sidechar = AOCharMovie(self.viewport) + self.sidechar.hide() + + self.bench = QtGui.QLabel(self.viewport) + bench = QtGui.QPixmap(AOpath + 'background/default/defensedesk.png') + self.court.setPixmap(QtGui.QPixmap(AOpath + 'background/default/defenseempty.png')) + self.bench.setPixmap(bench) + + self.effectview = AOMovie(self.viewport) + + self.chatbox = QtGui.QLabel(self.viewport) + chatbox = QtGui.QPixmap(AO2XPpath + 'themes/default/chatmed.png') + self.chatboxheight = chatbox.size().height() + self.chatbox.setPixmap(chatbox) + self.chatbox.move(0, 192*2 - self.chatboxheight) + + self.text = QtGui.QLabel(self.chatbox) + self.text.setWordWrap(True) + self.text.resize(250, 96) + self.text.move(6, 20) + self.text.setStyleSheet('color: white') + self.text.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) + + self.ao2text = QtGui.QTextEdit(self.chatbox) + self.ao2text.setFrameStyle(QtGui.QFrame.NoFrame) + self.ao2text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.ao2text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.ao2text.setReadOnly(True) + self.ao2text.setGeometry(2, 16, 240+10, 96) + self.ao2text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.ao2text.setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white") + + self.name = QtGui.QLabel(self.chatbox) + self.name.setStyleSheet('color: white') + self.name.move(5, 0) + self.name.resize(248, self.name.sizeHint().height()) + self.wtceview = WTCE_View(self) + self.WTCEsignal.connect(self.wtceview.showWTCE) + + self.objectionview = AOMovie(self.viewport) + self.objectionview.done.connect(self.objection_done) + + self.whiteflashlab = QtGui.QLabel(self.viewport) + self.whiteflashlab.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/realizationflash.png')) + self.whiteflashlab.setGeometry(0, 0, 256*2, 192*2) + self.whiteflashlab.hide() + self.whiteflash = QtCore.QTimer() + self.whiteflash.setSingleShot(False) + self.whiteflash.timeout.connect(partial(self.setWhiteFlash, False)) + + self.screenshake = QtCore.QTimer() + self.screenshake.timeout.connect(self.screenShakeTick) + self.shakes_remaining = 0 + + self.ooclog = ChatLogs(self, 1) + self.ooclog.setReadOnly(True) + p = self.ooclog.viewport().palette() + p.setColor(self.ooclog.viewport().backgroundRole(), QtGui.QColor(139,139,139)) + self.ooclog.viewport().setPalette(p) + self.ooclog.textChanged.connect(self.ooclog_update) + + self.oocnameinput = QtGui.QLineEdit(self) + self.oocnameinput.setPlaceholderText('Enter a name...') + self.oocnameinput.setStyleSheet('background-color: rgb(139, 139, 139);') + + self.oocinput = QtGui.QLineEdit(self) + self.oocinput.setPlaceholderText('Server chat/OOC chat...') + self.oocinput.setStyleSheet('background-color: rgb(139, 139, 139);') + self.oocinput.returnPressed.connect(self.onOOCreturn) + + self.ooclogin = QtGui.QPushButton("Login", self) + self.ooclogin.clicked.connect(self.onOOCLoginBtn) + + self.musicitems = QtGui.QListWidget(self) + self.musicitems.itemDoubleClicked.connect(self.onMusicClick) + + self.gametabs = QtGui.QTabWidget(self) + self.gametab_log = QtGui.QWidget() # the IC chat log + self.gametab_evidence = QtGui.QWidget() # court record + self.gametab_msgqueue = QtGui.QWidget() # IC messages pending to be sent + self.gametab_iniswap = QtGui.QWidget() # self explanatory + self.gametab_mute = QtGui.QWidget() # mute a player + self.gametab_pair = QtGui.QWidget() # AO2 pair + self.gametab_misc = QtGui.QWidget() # ao2xp misc/fun stuff + + self.icLog = ChatLogs(self.gametab_log, 0, self.ooclog.logfile) + self.icLog.setReadOnly(True) + self.icLog.textChanged.connect(self.icLogChanged) + + self.evidencedropdown = QtGui.QComboBox(self.gametab_evidence) + self.evidencedropdown.currentIndexChanged.connect(self.changeEvidence) + self.evidencedesc = QtGui.QTextEdit(self.gametab_evidence) + self.evidencedesc.setReadOnly(True) + self.evidenceimage = QtGui.QLabel(self.gametab_evidence) + self.evidenceimage.setPixmap(QtGui.QPixmap(AOpath + 'evidence/empty.png')) + self.evidenceimage.show() + self.evidenceadd = QtGui.QPushButton(self.gametab_evidence) + self.evidenceadd.setText('Add') + self.evidenceadd.clicked.connect(self.onAddEvidence) + self.evidenceedit = QtGui.QPushButton(self.gametab_evidence) + self.evidenceedit.setText('Edit') + self.evidenceedit.clicked.connect(self.onEditEvidence) + self.evidencedelete = QtGui.QPushButton(self.gametab_evidence) + self.evidencedelete.setText('Delete') + self.evidencedelete.clicked.connect(self.onDeleteEvidence) + self.evidencepresent = PresentButton(self, self.gametab_evidence) + + self.msgqueueList = QtGui.QListWidget(self.gametab_msgqueue) + self.msgqueueList.itemClicked.connect(self.onClicked_msgqueue) + self.removeQueue = QtGui.QPushButton(self.gametab_msgqueue) + self.removeQueue.setText('Delete') + self.removeQueue.clicked.connect(self.onClicked_removeQueue) + + self.unmutedlist = QtGui.QListWidget(self.gametab_mute) + self.mutedlist = QtGui.QListWidget(self.gametab_mute) + self.mutebtn = QtGui.QPushButton(self.gametab_mute) + self.unmutebtn = QtGui.QPushButton(self.gametab_mute) + self.notmutedlabel = QtGui.QLabel(self.gametab_mute) + self.mutedlabel = QtGui.QLabel(self.gametab_mute) + self.notmutedlabel.setText('Not muted') + self.mutedlabel.setText('Muted') + self.mutebtn.setText('>>') + self.unmutebtn.setText('<<') + self.mutebtn.clicked.connect(self.onMuteClick) + self.unmutebtn.clicked.connect(self.onUnmuteClick) + self.mutedlist.itemClicked.connect(self.changeMuteIndex) + self.unmutedlist.itemClicked.connect(self.changeUnmuteIndex) + + self.iniswaplist = QtGui.QComboBox(self.gametab_iniswap) + self.iniswaplist.currentIndexChanged.connect(self.iniswap_index_change) + self.iniswapconfirm = QtGui.QPushButton(self.gametab_iniswap) + self.iniswapconfirm.setText('Swap') + self.iniswapconfirm.clicked.connect(self.iniswap_confirm) + self.iniswapreset = QtGui.QPushButton(self.gametab_iniswap) + self.iniswapreset.setText('Reset') + self.iniswapreset.clicked.connect(self.resetIniSwap) + self.iniswapinfo = QtGui.QLabel(self.gametab_iniswap) + self.iniswapinfo.setText('Not swapped') + self.iniswaprefresh = QtGui.QPushButton(self.gametab_iniswap) + self.iniswaprefresh.setText('Refresh characters') + self.iniswaprefresh.clicked.connect(self.loadSwapCharacters) + + self.paircheckbox = QtGui.QCheckBox(self.gametab_pair) + self.paircheckbox.setChecked(False) + self.pairdropdown = QtGui.QComboBox(self.gametab_pair) + self.pairoffset = QtGui.QSlider(QtCore.Qt.Horizontal, self.gametab_pair) + self.pairoffset.setRange(-100, 100) + self.pairoffset.setValue(0) + self.pairoffset_l = QtGui.QLabel("X offset", self.gametab_pair) + self.ypairoffset = QtGui.QSlider(QtCore.Qt.Vertical, self.gametab_pair) + self.ypairoffset.setRange(-100, 100) + self.ypairoffset.setValue(0) + self.ypairoffset_l = QtGui.QLabel("Y offset", self.gametab_pair) + self.pairoffsetreset = QtGui.QPushButton("Reset", self.gametab_pair) + self.pairoffsetreset.clicked.connect(self.resetOffsets) + self.pair_order = QtGui.QComboBox(self.gametab_pair) + self.pair_order.addItem("Front") + self.pair_order.addItem("Behind") + self.pair_order_l = QtGui.QLabel("Pairing order", self.gametab_pair) + + self.misc_layout = QtGui.QVBoxLayout(self.gametab_misc) + self.misc_layout.setAlignment(QtCore.Qt.AlignTop) + self.mocktext = QtGui.QCheckBox() + self.mocktext.setChecked(False) + self.mocktext.setText(mockStr("mock text")) + self.spacebartext = QtGui.QCheckBox() + self.spacebartext.setChecked(False) + self.spacebartext.setText("S p a c i n g") + self.autocaps = QtGui.QCheckBox() + self.autocaps.setChecked(False) + self.autocaps.setText("Automatic caps and period") + self.misc_layout.addWidget(self.mocktext) + self.misc_layout.addWidget(self.spacebartext) + self.misc_layout.addWidget(self.autocaps) + + self.gametabs.addTab(self.gametab_log, 'Game log') + self.gametabs.addTab(self.gametab_evidence, 'Evidence') + self.gametabs.addTab(self.gametab_msgqueue, 'Message queue') + self.gametabs.addTab(self.gametab_mute, 'Mute') + self.gametabs.addTab(self.gametab_iniswap, 'Easy IniSwap') + self.gametabs.addTab(self.gametab_pair, 'Pair') + self.gametabs.addTab(self.gametab_misc, 'Misc') + + self.icchatinput = QtGui.QLineEdit(self) + self.icchatinput.setGeometry(0, 192, 256, 23) + self.icchatinput.returnPressed.connect(self.onICreturn) + self.icchatinput.setPlaceholderText('Game chat') + + self.emotedropdown = QtGui.QComboBox(self) + self.emotedropdown.setGeometry(192, 344, 128, 20) + self.emotedropdown.currentIndexChanged.connect(partial(self.changeEmote, True)) + + self.colordropdown = QtGui.QComboBox(self) + self.colordropdown.setGeometry(192, 376, 72, 20) + self.colordropdown.currentIndexChanged.connect(self.setChatColor) + + self.posdropdown = QtGui.QComboBox(self) + self.posdropdown.addItems(["def", "pro", "wit", "hld", "hlp", "jud"]) + self.posdropdown.setGeometry(self.emotedropdown.x() + self.emotedropdown.size().width() + 8, 344, 64, 20) + self.posdropdown.currentIndexChanged.connect(self.setPosition) + + self.flipbutton = QtGui.QCheckBox(self) + self.flipbutton.stateChanged.connect(self.changeFlipCheck) + self.flipbutton.setText('Mirror emote') + self.flipbutton.resize(self.flipbutton.sizeHint()) + self.flipbutton.move(272, 240) + + self.sfxbutton = QtGui.QCheckBox(self) + self.sfxbutton.setChecked(True) + self.sfxbutton.stateChanged.connect(self.changeSfxCheck) + self.sfxbutton.setText('Play pre-animation') + self.sfxbutton.resize(self.sfxbutton.sizeHint()) + self.sfxbutton.move(272, 272-12) + + self.nointerruptbtn = QtGui.QCheckBox(self) + self.nointerruptbtn.setChecked(False) + self.nointerruptbtn.setText('No Interrupt') + self.nointerruptbtn.resize(self.nointerruptbtn.sizeHint()) + self.nointerruptbtn.move(272, 272+8) + + # AO 2.8 + self.additivebtn = QtGui.QCheckBox(self) + self.additivebtn.setChecked(False) + self.additivebtn.setText('Additive text') + self.additivebtn.resize(self.additivebtn.sizeHint()) + self.additivebtn.move(272+60, 272+28) + self.additivebtn.clicked.connect(self.onAdditiveCheck) + + self.deskbtn = QtGui.QCheckBox(self) + self.deskbtn.setChecked(True) + self.deskbtn.setText('Desk') + self.deskbtn.resize(self.nointerruptbtn.sizeHint()) + self.deskbtn.move(self.flipbutton.x()+96, self.flipbutton.y()) + + self.effectdropdown = QtGui.QComboBox(self) + self.effectdropdown.setGeometry(272+60, 272+28+18, 88, 20) + + self.changechar = QtGui.QPushButton(self) + self.changechar.setText('Switch character') + self.changechar.setGeometry(10, 344, 121, 23) + self.changechar.clicked.connect(self.onClick_changeChar) + self.callmodbtn = QtGui.QPushButton(self) + self.callmodbtn.setText('Call mod') + self.callmodbtn.setGeometry(10, 376, 71, 23) + self.callmodbtn.clicked.connect(self.onClick_callMod) + + self.settingsbtn = QtGui.QPushButton("Settings", self) + self.settingsbtn.setGeometry(self.callmodbtn.x()+self.callmodbtn.size().width()+8, 376, self.settingsbtn.sizeHint().width(), 23) + self.settingsbtn.clicked.connect(self.gamewindow.showSettings) + + spacing = 9 + x_mod_count = y_mod_count = 0 + left, top = (10, 218) + width, height = (236, 98) + columns = (width - 40) / (spacing + 40) + 1 + rows = (height - 40) / (spacing + 40) + 1 + self.max_emotes_on_page = columns * rows + self.emotebuttons = [] + for i in range(self.max_emotes_on_page): + x_pos = (40 + spacing) * x_mod_count + y_pos = (40 + spacing) * y_mod_count + self.emotebuttons.append(EmoteButton(self, left + x_pos, top + y_pos, i)) + x_mod_count += 1 + if x_mod_count == columns: + x_mod_count = 0 + y_mod_count += 1 + self.emotebuttons[i].show() + + self.current_emote_page = 0 + self.prevemotepage = BackEmoteButton(self, 0, 253) + self.prevemotepage.hide() + self.nextemotepage = NextEmoteButton(self, 236, 253) + self.nextemotepage.show() + self.realizationbtn = buttons.AOToggleButton(self, 265, 192, "realization") + self.realizationbtn.clicked.connect(self.onRealizationButton) + self.realizationsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-realization.wav', 0, 0, 0) + self.shakebtn = buttons.AOToggleButton(self, 265+42, 192, "screenshake") # AO 2.8 + self.customobject = buttons.CustomObjection(self, 250, 312) + self.holditbtn = buttons.Objections(self, 10, 312, 1) + self.objectbtn = buttons.Objections(self, 90, 312, 2) + self.takethatbtn = buttons.Objections(self, 170, 312, 3) + self.objectsnd = None + self.defensebar = buttons.PenaltyBars(self, 1) + self.prosecutionbar = buttons.PenaltyBars(self, 2) + self.defensebar.moveBar(265, 164) + self.prosecutionbar.moveBar(265, 178) + self.defensebar.minusClicked.connect(self.penaltyBarMinus) + self.defensebar.plusClicked.connect(self.penaltyBarPlus) + self.prosecutionbar.minusClicked.connect(self.penaltyBarMinus) + self.prosecutionbar.plusClicked.connect(self.penaltyBarPlus) + self.wtcebtn_1 = buttons.WTCEbuttons(self, 256, 0, 0) + self.wtcebtn_2 = buttons.WTCEbuttons(self, 256 + self.wtcebtn_1.size().width(), 0, 1) + self.notguiltybtn = buttons.WTCEbuttons(self, 256, self.wtcebtn_1.size().height(), 2, 0) + self.guiltybtn = buttons.WTCEbuttons(self, 256 + self.notguiltybtn.size().width(), self.wtcebtn_2.size().height(), 2, 1) + self.wtcebtn_1.clicked.connect(self.WTCEbuttonPressed) + self.wtcebtn_2.clicked.connect(self.WTCEbuttonPressed) + self.notguiltybtn.clicked.connect(self.WTCEbuttonPressed) + self.guiltybtn.clicked.connect(self.WTCEbuttonPressed) + self.wtcebtn_1.show() + self.wtcebtn_2.show() + self.notguiltybtn.show() + self.guiltybtn.show() + self.presenting = -1 + self.presentedevi = QtGui.QLabel(self) + self.presentedevi.setGeometry(16, 16, 70, 70) + self.presentedevi.hide() + + self.showname = "" + self.shownameedit = QtGui.QLineEdit(self) + self.shownameedit.textChanged.connect(self.onChangeShowname) + self.shownameedit.setGeometry(self.colordropdown.x()+self.colordropdown.width()+8, self.colordropdown.y(), 144, 20) + self.shownameedit.setPlaceholderText("Showname") + + self.musicslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) + self.soundslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) + self.blipslider = QtGui.QSlider(QtCore.Qt.Horizontal, self) + self.musicslider.setRange(0, 100) + self.soundslider.setRange(0, 100) + self.blipslider.setRange(0, 100) + self.musicslider.sliderMoved.connect(self.changeMusicVolume) + self.soundslider.sliderMoved.connect(self.changeSoundVolume) + self.blipslider.valueChanged.connect(self.changeBlipVolume) + self.sliderlabel1 = QtGui.QLabel("Music", self) + self.sliderlabel2 = QtGui.QLabel("SFX", self) + self.sliderlabel3 = QtGui.QLabel("Blips", self) + + self.pinglabel = QtGui.QLabel(self) + + self.name.show() + self.char.show() + self.court.show() + self.bench.show() + self.chatbox.show() + + self.areas = [] + self.muteselected = -1 + self.unmuteselected = -1 + self.muted = [] + self.mychar = -1 + self.mychatcolor = 0 + self.charemotes = [] + self.selectedemote = 0 + self.charname = '' + self.charside = 'def' + self.msgqueue = [] + self.selectedmsg = -1 + self.evidence = [] + self.selectedevi = -1 + self.present = False + self.myflip = 0 + self.playsfx = 1 + self.loadSwapCharacters() + self.iniswaplist.setCurrentIndex(0) + self.evidence_editor = EditEvidenceDialog(self) + + self.connect(self, QtCore.SIGNAL('showMessage(QString, QString, QString)'), self.showMessage) + self.setBackground('default') + + self.charselect = charselect.charselect(self) + + def resetOffsets(self): + self.pairoffset.setValue(0) + self.ypairoffset.setValue(0) + + def screenShakeTick(self): + self.shakes_remaining -= 1 + shakeforce = 8 + if self.shakes_remaining: + self.court.move(random.randint(-shakeforce, shakeforce), random.randint(-shakeforce, shakeforce)) + self.zoom.move(random.randint(-shakeforce, shakeforce), random.randint(-shakeforce, shakeforce)) + self.char.move(self.char.xx + random.randint(-shakeforce, shakeforce), self.char.yy + random.randint(-shakeforce, shakeforce), True) + self.sidechar.move(self.sidechar.xx + random.randint(-shakeforce, shakeforce), self.sidechar.yy + random.randint(-shakeforce, shakeforce), True) + self.chatbox.move(random.randint(-shakeforce, shakeforce), 192*2 - self.chatboxheight + random.randint(-shakeforce, shakeforce)) + self.ao2text.move(-self.chatbox.x()+2, (192-self.chatboxheight-self.chatbox.y())+16) + self.text.move(-self.chatbox.x()+6, (192-self.chatboxheight-self.chatbox.y())+20) + else: + self.court.move(0,0) + self.zoom.move(0,0) + self.char.move(self.char.xx, self.char.yy, True) + self.sidechar.move(self.sidechar.xx, self.sidechar.yy, True) + self.chatbox.move(0, 192-self.chatboxheight) + self.ao2text.move(2,16) + self.text.move(6,20) + self.screenshake.stop() + + def onAdditiveCheck(self): + if self.additivebtn.isChecked(): + self.icchatinput.home(False) + self.icchatinput.insert(" ") + self.icchatinput.end(False) + self.icchatinput.setFocus() + + def onRealizationButton(self): + if self.realizationbtn.isPressed(): + self.effectdropdown.setCurrentIndex(1) # realization + elif self.effectdropdown.currentText() == "realization": + self.effectdropdown.setCurrentIndex(0) + + def onOOCLoginBtn(self): + password, ok = QtGui.QInputDialog.getText(self, "Login as moderator", "Enter password.") + if password and ok: + self.sendOOCchat(self.oocnameinput.text().toUtf8(), "/login "+password.toUtf8()) + + def setPing(self, newping): + self.pinglabel.setText("Ping: %d" % newping) + + def setPosition(self, ind): + if not self.oocnameinput.text(): + self.oocnameinput.setText("unnamed") + self.posdropdown.setCurrentIndex(ind) + self.charside = str(self.posdropdown.itemText(ind)) + self.setJudgeButtons() + + server_is_2_8 = "additive" in self.features and "looping_sfx" in self.features and "effects" in self.features + if server_is_2_8: + self.tcp.send("SP#"+self.charside+"#%") # all hail new AO 2.8 packet + else: + self.sendOOCchat(self.oocnameinput.text().toUtf8(), "/pos "+self.charside) + + def changeMusicVolume(self, value): + if self.music: + audio.sethandleattr(self.music, BASS_ATTRIB_VOL, value / 100.0) + + def changeSoundVolume(self, value): + if self.sound: + audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, value / 100.0) + audio.sethandleattr(self.realizationsnd, BASS_ATTRIB_VOL, value / 100.0) + audio.sethandleattr(self.wtcesfx, BASS_ATTRIB_VOL, value / 100.0) + audio.sethandleattr(self.guiltysfx, BASS_ATTRIB_VOL, value / 100.0) + audio.sethandleattr(self.notguiltysfx, BASS_ATTRIB_VOL, value / 100.0) + if self.modcall: + audio.sethandleattr(self.modcall, BASS_ATTRIB_VOL, value / 100.0) + + def changeBlipVolume(self, value): + if self.blipsnd: + audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, value / 100.0) + + def setJudgeButtons(self): + if self.charside == 'jud': + self.defensebar.minusbtn.show() + self.defensebar.plusbtn.show() + self.prosecutionbar.minusbtn.show() + self.prosecutionbar.plusbtn.show() + self.wtcebtn_1.show() + self.wtcebtn_2.show() + self.notguiltybtn.show() + self.guiltybtn.show() + else: + self.defensebar.minusbtn.hide() + self.defensebar.plusbtn.hide() + self.prosecutionbar.minusbtn.hide() + self.prosecutionbar.plusbtn.hide() + self.wtcebtn_1.hide() + self.wtcebtn_2.hide() + self.notguiltybtn.hide() + self.guiltybtn.hide() + + def onChangeShowname(self, text): + self.showname = str(text.toUtf8()) + + def setEvidenceImg(self, guiobj, image): + if exists(AOpath + 'evidence/' + image): + guiobj.setPixmap(QtGui.QPixmap(AOpath + "evidence/%s" % image)) + else: + guiobj.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/evidence_selected.png')) + if ini.read_ini_bool("AO2XP.ini", "General", "download evidence", True): + url = "base/evidence/"+image.lower() + url = url.replace("evidence/../", "") + path = AOpath+"evidence/"+image + path = path.replace("evidence/../", "") + thread.start_new_thread(download_thread, (url, path)) + + def changeUnmuteIndex(self, item): + for i in range(self.unmutedlist.count()): + if self.unmutedlist.item(i) == item: + self.muteselected = i + + def changeMuteIndex(self, item): + for i in range(self.mutedlist.count()): + if self.mutedlist.item(i) == item: + self.unmuteselected = i + + def onMuteClick(self): + if self.unmutedlist.count() == 0: + return QtGui.QMessageBox.warning(self, 'smh', 'you muted everyone\nhow does it feel?') + if self.muteselected == -1: + return QtGui.QMessageBox.warning(self, 'hey genius', 'who exactly are you muting?\nclick on their name then on the >> button') + for i in range(len(self.charlist)): + if self.charlist[i][0] == self.unmutedlist.item(self.muteselected).text(): + self.muted.append(i) + self.muted.sort() + self.muteselected = -1 + break + + self.unmutedlist.clear() + self.mutedlist.clear() + for i in range(len(self.charlist)): + if i in self.muted: + self.mutedlist.addItem(self.charlist[i][0]) + else: + self.unmutedlist.addItem(self.charlist[i][0]) + + def onUnmuteClick(self): + if self.mutedlist.count() == 0: + return QtGui.QMessageBox.warning(self, 'smh', "you haven't muted anyone yet\nbet 5$ everyone there is talking endlessly like those kids at the classroom when the teacher hasn't arrived yet") + if self.unmuteselected == -1: + return QtGui.QMessageBox.warning(self, 'hey genius', 'who exactly are you unmuting?\nclick on their name then on the >> button') + for char in self.charlist: + if char[0] == self.mutedlist.item(self.unmuteselected).text(): + del self.muted[self.unmuteselected] + self.unmuteselected = -1 + break + + self.unmutedlist.clear() + self.mutedlist.clear() + for i in range(len(self.charlist)): + if i in self.muted: + self.mutedlist.addItem(self.charlist[i][0]) + else: + self.unmutedlist.addItem(self.charlist[i][0]) + + def penaltyBarMinus(self, barType): + netmsg = 'HP#' + str(barType) + '#' + if barType == 1: + if self.defensebar.getHealth() <= 0: + return + netmsg += str(self.defensebar.getHealth() - 1) + '#' + elif barType == 2: + if self.prosecutionbar.getHealth() <= 0: + return + netmsg += str(self.prosecutionbar.getHealth() - 1) + '#' + netmsg += '%' + self.tcp.send(netmsg) + + def penaltyBarPlus(self, barType): + netmsg = 'HP#' + str(barType) + '#' + if barType == 1: + if self.defensebar.getHealth() >= 10: + return + netmsg += str(self.defensebar.getHealth() + 1) + '#' + elif barType == 2: + if self.prosecutionbar.getHealth() >= 10: + return + netmsg += str(self.prosecutionbar.getHealth() + 1) + '#' + netmsg += '%' + self.tcp.send(netmsg) + + def setWhiteFlash(self, on, realizationtype=0, msec=0): + self.whiteflashlab.setVisible(on) + if realizationtype == 1: + self.playRealization() + if msec: + self.whiteflash.start(msec) + + def setScreenShake(self, on, amount=20): + self.shakes_remaining = amount if on else 1 + self.screenshake.start(25) + + def WTCEbuttonPressed(self, type, variant): + if type != 2: + self.tcp.send('RT#testimony' + str(type + 1) + '#%') + else: + self.tcp.send("RT#judgeruling#" +str(variant)+ "#%") + + def onPVPacket(self, charname): + exec open(AO2XPpath+"ao2xp_themes/"+get_option("General", "theme", "default")+"/theme.py") + if not self.swapping: + self.loadCharacter(charname) + + def loadCharacter(self, charname): + self.msgqueueList.clear() + self.msgqueue = [] + self.effectdropdown.clear() + self.emotedropdown.clear() + self.charemotes = [] + self.selectedemote = 0 + self.current_emote_page = 0 + + effectslist = ini.get_effects(charname) + self.effectdropdown.setVisible(bool(effectslist)) + if effectslist: + effectslist.insert(0, "No effect") + self.effectdropdown.addItems(effectslist) + + self.charname = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "options", "name", charname) + self.charside = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "options", "side", "def") + self.posdropdown.setCurrentIndex(self.posdropdown.findText(self.charside)) + self.setJudgeButtons() + for emoteind in range(1, ini.read_ini_int(AOpath+"characters/"+self.charname+"/char.ini", "emotions", "number") + 1): + if emoteind == 1: + suffix = 'on' + else: + suffix = 'off' + + emote = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "emotions", str(emoteind), 'normal#(a)normal#normal#0#') + sound = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundn", str(emoteind), '1') + soundt = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundt", str(emoteind), '0') + soundl = ini.read_ini(AOpath + 'characters/' + charname + '/char.ini', "soundl", str(emoteind), '0') # AO 2.8 + emotelist = emote.split('#') + del emotelist[len(emotelist) - 1] + emotelist.append(sound) + emotelist.append(soundt) + emotelist.append(soundl) # AO 2.8 + self.charemotes.append(emotelist) + if emotelist[0]: + self.emotedropdown.addItem(emotelist[0]) + else: + self.emotedropdown.addItem(emotelist[1] + ' ' + emotelist[2]) + + self.emotedropdown.setCurrentIndex(0) + self.set_emote_page() + + def set_emote_page(self): + if self.mychar < 0: + return + self.prevemotepage.hide() + self.nextemotepage.hide() + + total_emotes = ini.read_ini_int(AOpath+"characters/"+self.charname+"/char.ini", "emotions", "number", 1) + for button in self.emotebuttons: + button.hide() + + total_pages = total_emotes / self.max_emotes_on_page + emotes_on_page = 0 + if total_emotes % self.max_emotes_on_page != 0: + total_pages += 1 + if total_pages > self.current_emote_page + 1: + emotes_on_page = self.max_emotes_on_page + else: + emotes_on_page = total_emotes % self.max_emotes_on_page + else: + emotes_on_page = self.max_emotes_on_page + if total_pages > self.current_emote_page + 1: + self.nextemotepage.show() + if self.current_emote_page > 0: + self.prevemotepage.show() + for n_emote in range(emotes_on_page): + n_real_emote = n_emote + self.current_emote_page * self.max_emotes_on_page + if n_real_emote == self.selectedemote: + self.emotebuttons[n_emote].setPixmap(QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(n_real_emote + 1) + '_on.png')) + else: + self.emotebuttons[n_emote].setPixmap(QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(n_real_emote + 1) + '_off.png')) + self.emotebuttons[n_emote].show() + + def iniswap_index_change(self, ind): + self.iniswapindex = ind + + def loadSwapCharacters(self): + self.charsfolder = [] + self.iniswaplist.clear() + for folder in os.listdir(AOpath + 'characters'): + if exists(AOpath + 'characters/' + folder + '/char.ini'): + self.charsfolder.append(folder) + self.iniswaplist.addItem(folder) + + def iniswap_confirm(self): + if self.charlist[self.mychar][0].lower() == self.charsfolder[self.iniswapindex].lower(): + self.resetIniSwap() + else: + self.swapping = True + self.iniswapinfo.setText('Swapped to ' + self.charsfolder[self.iniswapindex]) + self.loadCharacter(self.charsfolder[self.iniswapindex]) + + def resetIniSwap(self): + self.swapping = False + self.iniswapinfo.setText('Not swapped') + self.loadCharacter(self.charlist[self.mychar][0]) + + def onAddEvidence(self): + self.evidence_editor.show() + + def onEditEvidence(self): + if not self.evidence: + return QtGui.QMessageBox.information(self, 'edit what?', "there's no evidence on the court record...") + self.evidence_editor.EditEvidence(self.selectedevi) + + def onDeleteEvidence(self): + if self.evidence: + self.tcp.send('DE#' + str(self.selectedevi) + '#%') + else: + self.tcp.send('DE#0#%') + + def onClick_callMod(self): + if "modcall_reason" in self.features: + reason, ok = QtGui.QInputDialog.getText(self, "Call a moderator", "Enter your reason.") + if ok and reason: + self.tcp.send("ZZ#"+reason.toUtf8()+"#%") + else: + self.tcp.send("ZZ#%") + + def onClick_changeChar(self): + #self.tcp.send('RD#%') + self.charselect.show() + + def changeFlipCheck(self, on): + if on == 2: + on = 1 + self.myflip = on + + def changeSfxCheck(self, on): + if on == 2: + on = 1 + self.playsfx = on + self.nointerruptbtn.setDisabled(not on) + if on == 0: + self.nointerruptbtn.setChecked(False) + + def onClicked_msgqueue(self, item): + for i in range(len(self.msgqueueList)): + if self.msgqueueList.item(i) == item: + self.selectedmsg = i + + def onClicked_removeQueue(self): + if self.selectedmsg == -1: + return QtGui.QMessageBox.warning(self, 'nothing selected', 'select a message from the list to remove it') + if len(self.msgqueueList) == 0: + return QtGui.QMessageBox.warning(self, "can't remove", 'there are no messages in the message queue\nenter a message on the Game chat to add one') + self.msgqueueList.takeItem(self.selectedmsg) + del self.msgqueue[self.selectedmsg] + + def changeEvidence(self, ind): + if ind < 0: + return + self.selectedevi = ind + self.evidencedesc.setText(self.evidence[ind][1]) + self.setEvidenceImg(self.evidenceimage, self.evidence[ind][2]) + + def changeEmote(self, dropdown, ind): + if ind == -1: + return + if not dropdown: + self.selectedemote = ind + self.current_emote_page * self.max_emotes_on_page + else: + self.selectedemote = ind + for button in self.emotebuttons: + if button.emoteid == ind: + button.setPixmap(QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(button.emoteid + self.current_emote_page * self.max_emotes_on_page + 1) + '_on.png')) + else: + button.setPixmap(QtGui.QPixmap(AOpath + 'characters/' + self.charname + '/emotions/button' + str(button.emoteid + self.current_emote_page * self.max_emotes_on_page + 1) + '_off.png')) + + def setChatColor(self, ind): + self.mychatcolor = ind + + def showMessage(self, type, *args, **kwargs): + if type == 'critical': + reply = QtGui.QMessageBox.critical(self, *args, **kwargs) + elif type == 'information': + reply = QtGui.QMessageBox.information(self, *args, **kwargs) + elif type == 'question': + reply = QtGui.QMessageBox.question(self, *args, **kwargs) + elif type == 'warning': + reply = QtGui.QMessageBox.warning(self, *args, **kwargs) + if self.willDisconnect: + self.stopMusic() + self.gamewindow.returnToMenu() + + def onMusicClick(self, item): + if "cccc_ic_support" in self.features and self.showname: + self.tcp.send('MC#' + item.text().toUtf8() + '#' + str(self.mychar) + '#' + self.showname + '#%') + else: + self.tcp.send('MC#' + item.text().toUtf8() + '#' + str(self.mychar) + '#%') + + def icLogChanged(self): + if self.icLog.verticalScrollBar().value() == self.icLog.verticalScrollBar().maximum(): self.icLog.verticalScrollBar().setValue(self.icLog.verticalScrollBar().maximum()) + + def ooclog_update(self): + if self.ooclog.verticalScrollBar().value() == self.ooclog.verticalScrollBar().maximum(): self.ooclog.verticalScrollBar().setValue(self.ooclog.verticalScrollBar().maximum()) + + def sendOOCchat(self, name, text): + self.tcp.send('CT#' + name + '#' + text + '#%') + + def onOOCreturn(self): + text = self.oocinput.text().toUtf8().replace('#', '').replace('%', '').replace('&', '').replace('$', '').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....... + ind = self.posdropdown.findText(str(text.split(" ")[1])) + if ind >= 0: self.posdropdown.setCurrentIndex(ind) + self.oocinput.clear() + return + + if self.mocktext.isChecked(): + text = mockStr(text) + if self.autocaps.isChecked(): + l = list(text) + l[0] = l[0].upper() + if l[-1] != ".": + l.append(".") + text = "".join(l).replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's") + + self.sendOOCchat(self.oocnameinput.text().toUtf8(), text) + self.oocinput.clear() + + def onICreturn(self): + text = str(self.icchatinput.text().toUtf8()).replace('#', '').replace('%', '').replace('&', '').replace('$', '').replace('/n', '\n') + if not text: + return + + if self.mocktext.isChecked(): + text = mockStr(text) + if self.autocaps.isChecked(): + l = list(text) + l[0] = l[0].upper() + if l[-1] != ".": + l.append(".") + text = "".join(l).replace(" i ", " I ").replace("i'm", "I'm").replace("it's", "It's") + if self.spacebartext.isChecked(): + l = list(text) + for i in range(1, len(l)+len(l)-1, 2): + l.insert(i, " ") + text = "".join(l) + + emote = self.charemotes[self.selectedemote] + if self.nointerruptbtn.isChecked(): + modifier = 0 + else: + modifier = self.playsfx + objection = 0 + if self.customobject.isPressed(): + objection = 4 + self.customobject.setPressed(False) + elif self.holditbtn.isPressed(): + objection = 1 + self.holditbtn.setPressed(False) + elif self.objectbtn.isPressed(): + objection = 2 + self.objectbtn.setPressed(False) + elif self.takethatbtn.isPressed(): + objection = 3 + self.takethatbtn.setPressed(False) + if emote[3] == '5': #zoom + if self.nointerruptbtn.isChecked(): + modifier = 5 + else: + if objection > 0: + modifier = 6 + else: + modifier = 5 + elif objection > 0: + if self.nointerruptbtn.isChecked(): + modifier = 0 + else: + modifier = 2 + + msg = "MS#" + + if "deskmod" in self.features: # visible desk modifier + msg += "%d#" % self.deskbtn.isChecked() + else: + msg += "chat#" + + msg += emote[1]+"#" #pre-anim + msg += self.charname+"#" + msg += emote[2]+"#" #anim + msg += text+"#" + msg += self.charside+"#" + msg += emote[4]+"#" #sfx + msg += str(modifier)+"#" #emote modifier + msg += str(self.mychar)+"#" #character ID + msg += emote[5]+"#" #sfx delay + msg += str(objection)+"#" + msg += str((self.selectedevi + 1) * int(self.present))+"#" #selected evidence + + if self.present: + self.present = False + self.evidencepresent.setPixmap(self.evidencepresent.button_off) + + if "flipping" in self.features: + msg += str(self.myflip)+"#" + else: + msg += str(self.mychar)+"#" # old AO servers send a second charID in the message because drunk fanat + + msg += str(int(self.realizationbtn.isPressed()))+"#" + msg += str(self.mychatcolor)+"#" + + if "cccc_ic_support" in self.features: + msg += self.showname+"#" # custom showname + if self.paircheckbox.isChecked(): + msg += str(self.pairdropdown.currentIndex()) # pair charID + if "effects" in self.features: + msg += "^%d#" % self.pair_order.currentIndex() # pair ordering + else: + msg += "#" + else: + msg += "-1#" + + # AO 2.8: always send offset + if "y_offset" in self.features: # AO 2.9 + msg += str(self.pairoffset.value()) + "&" + str(-self.ypairoffset.value()) + "#" + else: + msg += str(self.pairoffset.value())+"#" + + msg += str(int(self.nointerruptbtn.isChecked()))+"#" # NoInterrupt(TM) + + if "looping_sfx" in self.features: # AO 2.8 + msg += emote[6]+"#" # loop sound? + msg += "%d#" % self.shakebtn.isPressed() # screen shake + emotes_to_check = [emote[1], "(b)"+emote[2], "(a)"+emote[2]] + effects_to_check = ["_FrameScreenshake", "_FrameRealization", "_FrameSFX"] + + for f_effect in effects_to_check: + packet = "" + for f_emote in emotes_to_check: + packet += f_emote + if ini.read_ini_bool("AO2XP.ini", "General", "network frame effects"): + sfx_frames = "|".join(ini.read_ini_tags(AOpath+"characters/"+self.charname+"/char.ini", f_emote + f_effect)) + if sfx_frames: + packet += "|" + sfx_frames + packet += "^" + msg += packet+"#" + + if "additive" in self.features: + msg += "%d#" % self.additivebtn.isChecked() + + if "effects" in self.features: + fx = self.effectdropdown.currentText() if self.effectdropdown.currentIndex() > 0 else "" + fx_sound = ini.get_effect_sound(fx, self.charname) + p_effect = ini.read_ini(AOpath+"characters/"+self.charname+"/char.ini", "options", "effects") + msg += fx + "|" + p_effect + "|" + fx_sound + "#" + self.effectdropdown.setCurrentIndex(0) + + msg += "%" + self.msgqueueList.addItem(self.icchatinput.text()) + self.msgqueue.append(msg) + + self.icchatinput.clear() + self.realizationbtn.setPressed(False) + self.shakebtn.setPressed(False) + + def setBackground(self, bg): + if not exists(AOpath + 'background/' + bg): + bg = 'default' + + for bgfile in [["side_def", "defenseempty"], + ["bench_def", "defensedesk"], + ["side_pro", "prosecutorempty"], + ["bench_pro", "prosecutiondesk"], + ["side_wit", "witnessempty"], + ["bench_wit", "stand"], + ["side_hld", "helperstand"], + ["bench_hld", "helperdesk"], + ["side_hlp", "prohelperstand"], + ["bench_hlp", "prohelperdesk"], + ["side_jud", "judgestand"], + ["bench_jud", "judgedesk"], + ["side_jur", "jurystand"], + ["bench_jur", "jurydesk"], + ["side_sea", "seancestand"], + ["bench_sea", "seancedesk"]]: + + bgimg = QtGui.QImage(AOpath + 'background/' + bg + '/' + bgfile[1] + '.png') + if not bgimg.isNull(): + if bgimg.size().width() != 256 or bgimg.size().height() != 192: + setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg.scaled(256*2, 192*2, transformMode=QtCore.Qt.SmoothTransformation))) + else: + setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg)) + else: + setattr(self, bgfile[0], QtGui.QPixmap.fromImage(bgimg)) + + + def netmsg_hp(self, type, health): + if type == 1: + self.defensebar.setHealth(health) + elif type == 2: + self.prosecutionbar.setHealth(health) + + def netmsg_ms(self, p_contents): + if len(p_contents) < 15: #this is already done on the TCP thread but i'll do it here anyway as well + return + + AO2chat = "cccc_ic_support" in self.features + + if int(p_contents[CHAR_ID]) in self.muted: # skip the self.chatmessage copy line below + return + + for n_string in range(self.chatmessage_size): + if n_string < len(p_contents) and (n_string < 16 or AO2chat): + self.m_chatmessage[n_string] = p_contents[n_string] + else: + self.m_chatmessage[n_string] = "" + + f_char_id = int(self.m_chatmessage[CHAR_ID]) + + if f_char_id < 0 or f_char_id >= len(self.charlist): + return + + f_showname = "" + if not self.m_chatmessage[SHOWNAME]: + f_showname = self.m_chatmessage[CHARNAME] + else: + f_showname = self.m_chatmessage[SHOWNAME] + + self.text_state = 0 + self.anim_state = 0 + self.objectionview.stop() + self.char.stop() + self.chat_tick_timer.stop() + self.presentedevi.hide() + + self.chatmessage_is_empty = self.m_chatmessage[CHATMSG] == " " or self.m_chatmessage[CHATMSG] == "" + + if self.msgqueue: + chatmsgcomp = str(self.msgqueue[0].split('#')[5]).decode('utf-8').replace('', '$').replace('', '%').replace('', '&').replace('', '#') + if f_char_id == self.mychar and self.m_chatmessage[CHATMSG] == chatmsgcomp: # our message showed up + del self.msgqueue[0] + self.msgqueueList.takeItem(0) + if self.additivebtn.isChecked(): + self.icchatinput.insert(" ") + + f_char = self.m_chatmessage[CHARNAME] + evidence = int(self.m_chatmessage[EVIDENCE])-1 + + t = time.localtime() + logcharname = f_char + if f_char.lower() != self.charlist[f_char_id][0].lower(): + logcharname = self.charlist[f_char_id][0] + ' (' + f_char.decode("utf-8") + ')' + + if self.m_chatmessage[SHOWNAME]: + try: + logcharname += " ("+self.m_chatmessage[SHOWNAME].decode("utf-8")+")" + except: + logcharname += " (???)" + + if evidence == -1: + self.icLog.append('[%d:%.2d] %s: %s' % (t[3], t[4], logcharname, self.m_chatmessage[CHATMSG])) + else: + eviname = '(NULL) %d' % evidence + try: + eviname = self.evidence[evidence][0] + except: + pass + + self.icLog.append('[%d:%.2d] %s: %s\n%s presented an evidence: %s' % (t[3], t[4], logcharname, self.m_chatmessage[CHATMSG], f_char, eviname)) + + self.is_additive = (self.m_chatmessage[ADDITIVE] == "1") + + custom_objection = "custom" + try: objection_mod = int(self.m_chatmessage[SHOUT_MOD]) + except: + if "4&" in self.m_chatmessage[SHOUT_MOD]: # custom objection name + objection_mod = 4 + custom_objection = self.m_chatmessage[SHOUT_MOD].split("4&")[1] # get the name + else: # just in case of mindfuckery + objection_mod = 0 + + if objection_mod <= 4 and objection_mod >= 1: + objections = ["holdit", "objection", "takethat", "custom_objections/"+custom_objection if custom_objection != "custom" else "custom"] + self.objectionview.play(objections[objection_mod-1], f_char) + self.playObjectionSnd(f_char, objection_mod) + + emote_mod = int(self.m_chatmessage[EMOTE_MOD]) + if emote_mod == 0: + self.m_chatmessage[EMOTE_MOD] = 1 + else: + self.handle_chatmessage_2() + + def set_text_color(self): + textcolor = int(self.m_chatmessage[TEXT_COLOR]) + + is_rainbow = textcolor == 6 + + if textcolor == 0: + color = QtGui.QColor(255, 255, 255) + elif textcolor == 1: + color = QtGui.QColor(0, 255, 0) + elif textcolor == 2: #OH FUCK MOD + color = QtGui.QColor(255, 0, 0) + elif textcolor == 3: + color = QtGui.QColor(255, 165, 0) + elif textcolor == 4: + color = QtGui.QColor(45, 150, 255) + elif textcolor == 5: + color = QtGui.QColor(255, 255, 0) + elif textcolor == 6: + color = QtGui.QColor(255, 255, 255) + elif textcolor == 7: + color = QtGui.QColor(255, 192, 203) + elif textcolor == 8: + color = QtGui.QColor(0, 255, 255) + + if is_rainbow: + self.text.show() + self.ao2text.hide() + else: + self.text.hide() + self.ao2text.show() + + style = "background-color: rgba(0, 0, 0, 0);\n" + style += "color: rgb("+str(color.red())+", "+str(color.green())+", "+str(color.blue())+")" + self.ao2text.setStyleSheet(style) + + def set_scene(self): + side = self.m_chatmessage[SIDE] + + if side == 'def': + self.court.setPixmap(self.side_def) + self.bench.setPixmap(self.bench_def) + self.bench.move(0, 192*2 - self.bench_def.size().height()) + self.presentedevi.move(170, 16) + elif side == 'pro': + self.court.setPixmap(self.side_pro) + self.bench.setPixmap(self.bench_pro) + self.bench.move(256*2 - self.bench_pro.size().width(), 192*2 - self.bench_pro.size().height()) + self.presentedevi.move(16, 16) + elif side == 'wit': + self.court.setPixmap(self.side_wit) + self.bench.setPixmap(self.bench_wit) + self.bench.move(0, 0) + self.presentedevi.move(16, 16) + elif side == 'hld': + self.court.setPixmap(self.side_hld) + self.bench.setPixmap(self.bench_hld) + self.presentedevi.move(16, 16) + elif side == 'hlp': + self.court.setPixmap(self.side_hlp) + self.bench.setPixmap(self.bench_hlp) + self.presentedevi.move(170, 16) + elif side == 'jud': + self.court.setPixmap(self.side_jud) + self.bench.setPixmap(self.bench_jud) + self.presentedevi.move(16, 16) + elif side == 'sea': + self.court.setPixmap(self.side_jud if self.side_sea.isNull() else self.side_sea) + self.bench.setPixmap(self.bench_jud if self.bench_sea.isNull() else self.bench_sea) + self.presentedevi.move(16, 16) + elif side == 'jur': + self.court.setPixmap(self.side_jud if self.side_jur.isNull() else self.side_jur) + self.bench.setPixmap(self.bench_jud if self.bench_jur.isNull() else self.bench_jur) + self.presentedevi.move(16, 16) + + deskmod = self.m_chatmessage[DESK_MOD] + if deskmod == "0" or (deskmod != "1" and (side in ("jud", "hld", "hlp"))): + self.bench.hide() + else: + self.bench.show() + + def objection_done(self): + self.handle_chatmessage_2() + + def handle_chatmessage_2(self): + self.zoom.setZoom(False) + self.char.stop() + self.effectview.stop() + + if not self.m_chatmessage[SHOWNAME]: + self.name.setText(self.m_chatmessage[CHARNAME]) + else: + self.name.setText(self.m_chatmessage[SHOWNAME].decode("utf-8")) + + self.chatbox.hide() + + self.set_scene() + self.set_text_color() + + f_message = self.m_chatmessage[CHATMSG] + if len(f_message) >= 2: + self.message_is_centered = f_message.startswith("~~") + else: + self.ao2text.setAlignment(QtCore.Qt.AlignLeft) + self.text.setAlignment(QtCore.Qt.AlignLeft) + + if self.m_chatmessage[FLIP] == "1": + self.char.set_flipped(True) + else: + self.char.set_flipped(False) + + side = self.m_chatmessage[SIDE] + emote_mod = int(self.m_chatmessage[EMOTE_MOD]) + + # AO 2.8: always offset player + hor_offset = vert_offset = 0 + + if "y_offset" in self.features: # AO 2.9 + keyword = "" if "" in self.m_chatmessage[SELF_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous + hor_offset = int(self.m_chatmessage[SELF_OFFSET].split(keyword)[0]) + vert_offset = int(self.m_chatmessage[SELF_OFFSET].split(keyword)[1]) if len(self.m_chatmessage[SELF_OFFSET].split(keyword)) > 1 else 0 + else: + hor_offset = int(self.m_chatmessage[SELF_OFFSET]) + + + if side == "def": + if hor_offset > 0 and vert_offset == 0: + vert_offset = hor_offset / 10 + elif side == "pro": + if hor_offset < 0 and vert_offset == 0: + vert_offset = -1 * hor_offset / 10 + + self.char.move(256 * hor_offset / 100, 192 * vert_offset / 100) + + # check if paired + if not self.m_chatmessage[OTHER_CHARID]: + self.sidechar.hide() + self.sidechar.move(0,0) + else: + if "effects" in self.features: + got_other_charid = int(self.m_chatmessage[OTHER_CHARID].split("^")[0]) + else: + got_other_charid = int(self.m_chatmessage[OTHER_CHARID]) + + 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]) + else: + pair_order = -1 + + hor2_offset = vert2_offset = 0 + if "y_offset" in self.features: # AO 2.9 + keyword = "" if "" in self.m_chatmessage[OTHER_OFFSET] else "&" # i don't think it's hdf's fault but this is still ridiculous + hor2_offset = int(self.m_chatmessage[OTHER_OFFSET].split(keyword)[0]) + vert2_offset = int(self.m_chatmessage[OTHER_OFFSET].split(keyword)[1]) if len(self.m_chatmessage[OTHER_OFFSET].split(keyword)) > 1 else 0 + else: + hor2_offset = int(self.m_chatmessage[OTHER_OFFSET]) + + if side == "def": + if hor2_offset > 0: + vert2_offset = hor2_offset / 10 + + elif side == "pro": + if hor2_offset < 0: + vert2_offset = -1 * hor2_offset / 10 + + if pair_order == -1: # pair ordering not supported + if hor2_offset >= hor_offset: + self.sidechar.raise_() + self.char.raise_() + else: + self.char.raise_() + self.sidechar.raise_() + elif pair_order == 0: # front + self.char.raise_() + self.sidechar.raise_() + elif pair_order == 1: # behind + self.sidechar.raise_() + self.char.raise_() + + self.sidechar.move(256 * hor2_offset / 100, 192 * vert2_offset / 100) + + self.bench.raise_() + self.chatbox.raise_() + self.effectview.raise_() + self.objectionview.raise_() + self.whiteflashlab.raise_() + + self.sidechar.set_flipped(self.m_chatmessage[OTHER_FLIP] == "1") + self.sidechar.play_idle(self.m_chatmessage[OTHER_NAME], self.m_chatmessage[OTHER_EMOTE]) + + else: + self.sidechar.hide() + self.sidechar.move(0, 0) + + if (emote_mod == 1 or emote_mod == 6) and self.m_chatmessage[PREANIM] != "-": + self.play_preanim(False) + elif emote_mod == 0 or emote_mod == 5 or self.m_chatmessage[PREANIM] == "-": + if self.m_chatmessage[NO_INTERRUPT] == "0" or self.m_chatmessage[PREANIM] == "-": + self.handle_chatmessage_3() + else: + self.play_preanim(True) + + def play_preanim(self, noninterrupting): + f_char = self.m_chatmessage[CHARNAME] + f_preanim = self.m_chatmessage[PREANIM] + + ao2_duration = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "time", "%"+f_preanim, -1) + text_delay = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "textdelay", f_preanim, -1) + sfx_delay = int(self.m_chatmessage[SFX_DELAY]) * 60 + + preanim_duration = 0 + if ao2_duration < 0: + preanim_duration = ini.read_ini_int(AOpath+"characters/"+f_char+"/char.ini", "time", f_preanim, -1) + else: + preanim_duration = ao2_duration + + anim_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".gif" + apng_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".apng" + webp_to_find = AOpath+"characters/"+f_char+"/"+f_preanim+".webp" + if (not exists(anim_to_find) and not exists(apng_to_find) and not exists(webp_to_find)) or preanim_duration < 0: + if noninterrupting: + self.anim_state = 4 + else: + self.anim_state = 1 + self.preanim_done() + + self.char.play_pre(f_char, f_preanim, preanim_duration) + if noninterrupting: + self.anim_state = 4 + else: + self.anim_state = 1 + + if sfx_delay > 0: + self.sfx_delay_timer.start(sfx_delay) + else: + self.play_sfx() + + if text_delay >= 0: + pass #text delay timer, but not now. + + if noninterrupting: + self.handle_chatmessage_3() + + def preanim_done(self): + self.anim_state = 1 + self.handle_chatmessage_3() + + def handle_chatmessage_3(self): + self.start_chat_ticking() + + f_evi_id = int(self.m_chatmessage[EVIDENCE]) + f_side = self.m_chatmessage[SIDE] + + emote_mod = int(self.m_chatmessage[EMOTE_MOD]) + + if f_evi_id > 0 and f_evi_id <= len(self.evidence): + f_image = self.evidence[f_evi_id-1][2] + is_left_side = not (f_side == "def" or f_side == "hlp" or f_side == "jud" or f_side == "jur") + + self.setEvidenceImg(self.presentedevi, f_image) + + if not is_left_side: + self.presentedevi.move(170, 16) + else: + self.presentedevi.move(16, 16) + self.presentedevi.show() + else: + self.presentedevi.hide() + + side = self.m_chatmessage[SIDE] + if emote_mod == 5 or emote_mod == 6: + self.bench.hide() + self.sidechar.hide() + self.char.move(0,0) + + if side == "pro" or side == "hlp" or side == "wit": + self.zoom.setZoom(True, 1) + else: + self.zoom.setZoom(True, 0) + + f_anim_state = 0 + text_is_blue = int(self.m_chatmessage[TEXT_COLOR]) == 4 + + if not text_is_blue and self.text_state == 1: + f_anim_state = 2 + self.entire_message_is_blue = False + else: + f_anim_state = 3 + self.entire_message_is_blue = True + + if f_anim_state <= self.anim_state: + return + + self.char.stop() + f_char = self.m_chatmessage[CHARNAME] + f_emote = self.m_chatmessage[ANIM] + + if f_anim_state == 2: + self.char.play_talking(f_char, f_emote) + self.anim_state = 2 + else: + self.char.play_idle(f_char, f_emote) + self.anim_state = 3 + + if exists(AOpath+"callwords.ini"): + callwords = [line.rstrip() for line in open(AOpath+"callwords.ini")] + for callword in callwords: + if callword.lower() in self.m_chatmessage[CHATMSG].lower(): + self.ooclog.append("%s called you." % f_char) + snd = audio.loadhandle(False, "word_call.wav", 0, 0, BASS_STREAM_AUTOFREE) + if snd: + audio.playhandle(snd, True) + break + + def do_effect(self, fx_name, fx_sound, p_char, p_folder): + effect = ini.get_effect(fx_name, p_char, p_folder) + if not effect: return + + if fx_sound: + self.playSound(fx_sound) + + if "effects" not in self.features: return + + self.effectview.set_play_once(False) + try: self.effectview.play(effect) + except: pass # Windows XP webp error with Pillow + print "effect", repr(effect) + + def start_chat_ticking(self): + if self.text_state != 0: + return + + if self.m_chatmessage[EFFECTS]: + fx_list = self.m_chatmessage[EFFECTS].split("|") + fx = fx_list[0] + fx_sound = "" + fx_folder = "" + + if len(fx_list) > 1: + fx_sound = fx_list[1] + if len(fx_list) > 2: + fx_folder = fx_list[1] + fx_sound = fx_list[2] + + if fx and fx not in ("-", "None"): + self.do_effect(fx, fx_sound, self.m_chatmessage[CHARNAME], fx_folder) + + elif self.m_chatmessage[REALIZATION] == "1": + self.setWhiteFlash(True, 1, 125) + + self.set_text_color() + + charid = int(self.m_chatmessage[CHAR_ID]) + if not self.is_additive or self.additive_char != charid: + self.ao2text.clear() + self.text.setText("") + self.additive_char = charid + + if self.chatmessage_is_empty: + self.text_state = 2 + return + + self.inline_color_stack = [] + + self.chatbox.show() + + self.tick_pos = 0 + self.blip_pos = 0 + self.inline_blue_depth = 0 + + self.current_display_speed = 3 + self.chat_tick_timer.start(self.message_display_speed[self.current_display_speed]) + + self.blip = self.charlist[charid][2] + + if exists(AOpath+"sounds/general/sfx-blip"+self.blip+".wav"): + self.blipsnd = audio.loadhandle(False, AOpath+"sounds/general/sfx-blip"+self.blip+".wav", 0, 0, 0) + elif exists(AOpath+"sounds/general/sfx-blip"+self.blip+".opus"): + self.blipsnd = audio.loadhandle(False, AOpath+"sounds/general/sfx-blip"+self.blip+".opus", 0, 0, 0) + elif exists(AOpath+"sounds/blips/"+self.blip+".wav"): + self.blipsnd = audio.loadhandle(False, AOpath+"sounds/blips/"+self.blip+".wav", 0, 0, 0) + elif exists(AOpath+"sounds/blips/"+self.blip+".opus"): + self.blipsnd = audio.loadhandle(False, AOpath+"sounds/blips/"+self.blip+".opus", 0, 0, 0) + else: + self.blipsnd = 0 + + audio.sethandleattr(self.blipsnd, BASS_ATTRIB_VOL, self.blipslider.value() / 100.0) + + emote_mod = int(self.m_chatmessage[EMOTE_MOD]) + if emote_mod in (0, 5) and self.m_chatmessage[SCREENSHAKE] == "1": + self.setScreenShake(True) + + self.text_state = 1 + + def chat_tick(self): + f_message = self.m_chatmessage[CHATMSG] + + self.chat_tick_timer.stop() + formatting_char = False + + if self.message_is_centered: + f_message = f_message.strip("~~") + + if self.tick_pos >= len(f_message): + self.text_state = 2 + if self.anim_state != 4: + self.anim_state = 3 + self.char.play_idle(self.m_chatmessage[CHARNAME], self.m_chatmessage[ANIM]) + else: + f_character2 = f_message[self.tick_pos] + f_character = QtCore.QString(f_character2) + + if f_character == " ": + self.text.setText(self.text.text() + " ") + self.ao2text.insertPlainText(" ") + + elif f_character == "\n" or f_character == "\r": + self.text.setText(self.text.text() + "\n") + self.ao2text.insertPlainText("\n") + + elif f_character == "\\" and not self.next_character_is_not_special: + self.next_character_is_not_special = True + formatting_char = True + + elif f_character == "{" and not self.next_character_is_not_special: + self.current_display_speed += 1 + formatting_char = True + + elif f_character == "}" and not self.next_character_is_not_special: + self.current_display_speed -= 1 + formatting_char = True + + elif f_character == "|" and not self.next_character_is_not_special: #orange. + if self.inline_color_stack: + if self.inline_color_stack[-1] == INLINE_ORANGE: + del self.inline_color_stack[-1] + else: + self.inline_color_stack.append(INLINE_ORANGE) + else: + self.inline_color_stack.append(INLINE_ORANGE) + formatting_char = True + + elif f_character == "(" and not self.next_character_is_not_special: #blue. + self.inline_color_stack.append(INLINE_BLUE) + self.ao2text.insertHtml("" + f_character + "") + + self.inline_blue_depth += 1 + if not self.entire_message_is_blue and self.anim_state != 4: + f_char = self.m_chatmessage[CHARNAME] + f_emote = self.m_chatmessage[ANIM] + self.char.play_idle(f_char, f_emote) + + elif f_character == ")" and not self.next_character_is_not_special and self.inline_color_stack: + if self.inline_color_stack[-1] == INLINE_BLUE: + del self.inline_color_stack[-1] + self.ao2text.insertHtml("" + f_character + "") + + if self.inline_blue_depth > 0: + self.inline_blue_depth -= 1 + + if not self.entire_message_is_blue: + if self.inline_blue_depth == 0 and self.anim_state != 4 and not (self.tick_pos+1 >= len(f_message)): + f_char = self.m_chatmessage[CHARNAME] + f_emote = self.m_chatmessage[ANIM] + self.char.play_talking(f_char, f_emote) + else: + self.next_character_is_not_special = True + self.tick_pos -= 1 + + elif f_character == "[" and not self.next_character_is_not_special: #gray. + self.inline_color_stack.append(INLINE_GRAY) + self.ao2text.insertHtml("" + f_character + "") + + elif f_character == "]" and not self.next_character_is_not_special and self.inline_color_stack: + if self.inline_color_stack[-1] == INLINE_GRAY: + del self.inline_color_stack[-1] + self.ao2text.insertHtml("" + f_character + "") + else: + self.next_character_is_not_special = True + self.tick_pos -= 1 + + elif f_character == "`" and not self.next_character_is_not_special: #green. + if self.inline_color_stack: + if self.inline_color_stack[-1] == INLINE_GREEN: + del self.inline_color_stack[-1] + else: + self.inline_color_stack.append(INLINE_GREEN) + else: + self.inline_color_stack.append(INLINE_GREEN) + formatting_char = True + + elif f_character == "~" and not self.next_character_is_not_special: #green. + if self.inline_color_stack: + if self.inline_color_stack[-1] == INLINE_RED: + del self.inline_color_stack[-1] + else: + self.inline_color_stack.append(INLINE_RED) + else: + self.inline_color_stack.append(INLINE_RED) + formatting_char = True + + elif f_character == "s" and self.next_character_is_not_special: # shake + self.setScreenShake(True) + self.next_character_is_not_special = False + + elif f_character == "f" and self.next_character_is_not_special: # flash + self.setWhiteFlash(True, 0, 75) + self.next_character_is_not_special = False + + elif f_character == "n" and self.next_character_is_not_special: # newline + self.text.setText(self.text.text() + "\n") + self.ao2text.insertPlainText("\n") + self.next_character_is_not_special = False + + else: + self.next_character_is_not_special = False + if self.inline_color_stack: + top_color = self.inline_color_stack[-1] + if top_color == INLINE_ORANGE: + self.ao2text.insertHtml("" + f_character + "") + elif top_color == INLINE_BLUE: + self.ao2text.insertHtml("" + f_character + "") + elif top_color == INLINE_GREEN: + self.ao2text.insertHtml("" + f_character + "") + elif top_color == INLINE_GRAY: + self.ao2text.insertHtml("" + f_character + "") + elif top_color == INLINE_RED: + self.ao2text.insertHtml("" + f_character + "") + else: + self.ao2text.insertHtml(f_character) + else: + if int(self.m_chatmessage[TEXT_COLOR]) == C_RAINBOW: + self.text.setText(self.text.text() + f_character) + else: + self.ao2text.insertHtml(f_character) + + if self.message_is_centered: + self.ao2text.setAlignment(QtCore.Qt.AlignCenter) + self.text.setAlignment(QtCore.Qt.AlignCenter) + else: + self.ao2text.setAlignment(QtCore.Qt.AlignLeft) + self.text.setAlignment(QtCore.Qt.AlignLeft) + + if f_message[self.tick_pos] != " " or self.blank_blip: + if self.blip_pos % self.blip_rate == 0 and not formatting_char: + self.blip_pos = 0 + audio.playhandle(self.blipsnd, True) + + self.blip_pos += 1 + + self.tick_pos += 1 + + if self.current_display_speed < 0: + self.current_display_speed = 0 + elif self.current_display_speed > 6: + self.current_display_speed = 6 + + if formatting_char: + self.chat_tick_timer.start(1) + else: + self.chat_tick_timer.start(self.message_display_speed[self.current_display_speed]) + + def playRealization(self): + audio.playhandle(self.realizationsnd, True) + + def playObjectionSnd(self, charname, objection): + if self.objectsnd: + if audio.handleisactive(self.objectsnd): + audio.stophandle(self.objectsnd) + audio.freehandle(self.objectsnd) + + objecting = ["holdit", "objection", "takethat", "custom"][objection-1] + + if objecting: + if exists(AOpath + 'characters/' + charname + '/' + objecting + '.wav'): + self.objectsnd = audio.loadhandle(False, AOpath + 'characters/' + charname + '/' + objecting + '.wav', 0, 0, 0) + elif exists(AOpath + 'characters/' + charname + '/' + objecting + '.opus'): + self.objectsnd = audio.loadhandle(False, AOpath + 'characters/' + charname + '/' + objecting + '.opus', 0, 0, 0) + else: + self.objectsnd = None + if ini.read_ini_bool("AO2XP.ini", "General", "download sounds", True): + thread.start_new_thread(download_thread, ("base/characters/"+charname.lower()+"/"+objecting.lower()+".wav", AOpath+"characters/"+charname.lower()+"/"+objecting.lower()+".wav")) + thread.start_new_thread(download_thread, ("base/characters/"+charname.lower()+"/"+objecting.lower()+".opus", AOpath+"characters/"+charname.lower()+"/"+objecting.lower()+".wav")) + + if exists(AOpath + 'sounds/general/sfx-objection.opus'): + self.objectsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.opus', 0, 0, 0) + else: + self.objectsnd = audio.loadhandle(False, AOpath + 'sounds/general/sfx-objection.wav', 0, 0, 0) + audio.sethandleattr(self.objectsnd, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0) + audio.playhandle(self.objectsnd, True) + + def play_sfx(self): + sfx_name = self.m_chatmessage[SFX] + if sfx_name == "1": + return + + self.playSound(sfx_name) + + def playSound(self, sfx): + if self.sound: + if audio.handleisactive(self.sound): + audio.stophandle(self.sound) + audio.freehandle(self.sound) + + if exists(AOpath + 'sounds/general/' + sfx + '.wav'): + self.sound = audio.loadhandle(False, AOpath + 'sounds/general/' + sfx + '.wav', 0, 0, 0) + audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0) + audio.playhandle(self.sound, True) + + elif exists(AOpath + 'sounds/general/' + sfx + '.opus'): + self.sound = audio.loadhandle(False, AOpath + 'sounds/general/' + sfx + '.opus', 0, 0, 0) + audio.sethandleattr(self.sound, BASS_ATTRIB_VOL, self.soundslider.value() / 100.0) + audio.playhandle(self.sound, True) + + def playMusic(self, mus): + if not mus.endswith(".mp3") and "===MUSIC START===.mp3" in self.musiclist: #vidya workaround + mus += ".mp3" + + if self.music: + if audio.handleisactive(self.music): + audio.stophandle(self.music) + audio.freehandle(self.music) + + if exists(AOpath + 'sounds/music/' + mus): + self.music = audio.loadhandle(False, AOpath + 'sounds/music/' + mus, 0, 0, BASS_SAMPLE_LOOP) + audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) + audio.playhandle(self.music, True) + + elif ini.read_ini_bool("AO2XP.ini", "General", "download music", True): + if mus.lower().startswith("http"): + self.music = audio.loadURLhandle(mus, 0, BASS_STREAM_BLOCK | BASS_SAMPLE_LOOP) + print "Trying to play", mus.lower() + else: + for bucket in buckets: + if not bucket: continue + print "music stream:", bucket+'base/sounds/music/' + mus.lower() + self.music = audio.loadURLhandle(bucket+'base/sounds/music/' + mus.lower(), 0, BASS_STREAM_BLOCK) + if self.music: break + + if self.music: + audio.sethandleattr(self.music, BASS_ATTRIB_VOL, self.musicslider.value() / 100.0) + audio.playhandle(self.music, True) + else: + print "Couldn't play music. Error", audio.getbasserror() + + def stopMusic(self): + if self.music: + if audio.handleisactive(self.music): + audio.stophandle(self.music) + audio.freehandle(self.music) + + def startGame(self, tcp, charlist, musiclist, background, evidence, areas, features=[], oocjoin=[], hplist=[], webAO_bucket=""): + self.willDisconnect = False + self.mychar = -1 + self.mychatcolor = 0 + self.tcp = tcp + self.charlist = charlist + self.musiclist = musiclist + self.evidence = evidence + self.areas = areas + self.features = features + + if "base/" in webAO_bucket: + webAO_bucket = webAO_bucket.replace("base/", "") + buckets[0] = webAO_bucket + + self.charselect.setCharList(charlist) + self.charselect.show() + + self.oocnameinput.setText(ini.read_ini("AO2XP.ini", "General", "OOC name")) + self.shownameedit.setText(ini.read_ini("AO2XP.ini", "General", "Showname")) + + self.pairdropdown.clear() + self.paircheckbox.setChecked(False) + if "cccc_ic_support" in features: + self.shownameedit.show() + self.nointerruptbtn.show() + self.paircheckbox.setDisabled(False) + self.paircheckbox.setText("Enable pairing") + for char in charlist: + self.pairdropdown.addItem(char[0]) + else: + self.shownameedit.hide() + self.nointerruptbtn.hide() + self.paircheckbox.setDisabled(True) + self.paircheckbox.setText("This server does not support pairing.") + + self.deskbtn.setDisabled("deskmod" not in features) + self.flipbutton.setVisible("flipping" in features) + self.customobject.setVisible("customobjections" in features) + self.ypairoffset.setVisible("y_offset" in features) + self.ypairoffset_l.setVisible("y_offset" in features) + + self.colordropdown.clear() + self.colordropdown.addItems(['white', 'green', 'red', 'orange', 'blue']) + if "yellowtext" in features: + self.colordropdown.addItems(['yellow', 'gay pride', 'pink', 'cyan']) + self.colordropdown.setCurrentIndex(self.mychatcolor) + + for hp in hplist: + self.healthbars.emit(hp[0], hp[1]) + + for char in self.charlist: + if not exists(AOpath + 'characters/' + char[0] + '/char.ini'): + continue + char[2] = get_char_ini(char[0], "options", "gender", "male") + + self.realizationbtn.setPressed(False) + self.customobject.setPressed(False) + self.mutedlist.clear() + self.unmutedlist.clear() + for char in self.charlist: + self.unmutedlist.addItem(char[0]) + + self.musicitems.clear() + self.evidencedropdown.clear() + for evi in evidence: + self.evidencedropdown.addItem(evi[0]) + + logstart = '--- Log started on ' + time.ctime() + ' ---' + if self.ooclog.toPlainText(): + self.ooclog.append("\n"+logstart) + else: + self.ooclog.append(logstart) + if self.icLog.toPlainText(): + self.icLog.append("\n"+logstart) + else: + self.icLog.append(logstart) + + self.setBackground(background) + for msg in oocjoin: + self.ooclog.append(msg) + + for song in musiclist: + songitem = QtGui.QListWidgetItem() + songitem.setText(song) + if exists(AOpath + 'sounds/music/' + song): + songitem.setBackgroundColor(QtGui.QColor(128, 255, 128)) + else: + songitem.setBackgroundColor(QtGui.QColor(255, 128, 128)) + self.musicitems.addItem(songitem) + + self.musicslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Music volume", 100)) + self.soundslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Sound volume", 100)) + self.blipslider.setValue(ini.read_ini_int("AO2XP.ini", "Audio", "Blip volume", 100)) + + #thread.start_new_thread(self.tcp_thread, ()) + self.tcpthread = TCP_Thread(self) + self.tcpthread.MS_Chat.connect(self.netmsg_ms) + self.tcpthread.newChar.connect(self.onPVPacket) + 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.showCharSelect.connect(self.charselect.show) + self.tcpthread.allEvidence.connect(self.allEvidence) + self.tcpthread.rainbowColor.connect(self.text.setStyleSheet) + self.tcpthread.start() + + def allEvidence(self, evi): + self.evidence = evi + if self.evidencedropdown.count() > 0: + self.evidencedropdown.clear() + for evi in self.evidence: + while len(evi) < 3: # new AO 2.9 bug where they never correctly escaped evidence name/desc/image on FantaProtocol + evi += [""] + evi[0] = decode_ao_str(evi[0].decode('utf-8')) + evi[1] = decode_ao_str(evi[1].decode('utf-8')) + evi[2] = decode_ao_str(evi[2].decode('utf-8')) + self.evidencedropdown.addItem(evi[0]) + + if not self.evidence: + self.evidencedropdown.setCurrentIndex(0) + self.evidencedesc.setText('.') + else: + self.evidencedropdown.setCurrentIndex(self.selectedevi) + +class PresentButton(QtGui.QLabel): + + def __init__(self, gamegui, parent): + super(PresentButton, self).__init__(parent) + self.gamegui = gamegui + self.button_off = QtGui.QPixmap(AO2XPpath + 'themes/default/present_disabled.png') + self.button_on = QtGui.QPixmap(AO2XPpath + 'themes/default/present.png') + self.setPixmap(self.button_off) + self.show() + + def mousePressEvent(self, event): + self.gamegui.present = not self.gamegui.present + if self.gamegui.present: + self.setPixmap(self.button_on) + else: + self.setPixmap(self.button_off) + + +class EditEvidenceDialog(QtGui.QDialog): + def __init__(self, gamegui): + super(EditEvidenceDialog, self).__init__() + self.gamegui = gamegui + self.setWindowTitle('Add evidence') + self.resize(512, 384) + self.setModal(True) + + self.eviname = QtGui.QLineEdit(self) + self.eviname.setGeometry(8, 8, 384, 24) + self.evidesc = QtGui.QTextEdit(self) + self.evidesc.setGeometry(8, 192, 496, 160) + self.evipicture = QtGui.QLabel(self) + self.filename = 'empty.png' + evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png') + self.evipicture.setPixmap(evipic) + self.evipicture.move(434, 8) + self.evipicture.show() + self.save = QtGui.QPushButton(self) + self.save.setText('Save') + self.save.clicked.connect(self.onSave) + self.save.move(256*2 - self.save.size().width() - 8, 384 - self.save.size().height()) + self.cancel = QtGui.QPushButton(self) + self.cancel.setText('Cancel') + self.cancel.clicked.connect(self.onCancel) + self.cancel.move(264, 384 - self.cancel.size().height()) + self.choosepic = QtGui.QComboBox(self) + self.filenames = [] + self.choosepic.setGeometry(376, 78, 128, 24) + files = os.listdir(AOpath + 'evidence') + fileslength = len(files) + i = 0 + while i < fileslength: + if not files[i].endswith('.png'): + del files[i] + fileslength = len(files) + i -= 1 + i += 1 + + for i in range(len(files)): + if files[i].endswith('.png'): + self.choosepic.addItem(files[i].strip('.png')) + self.filenames.append(files[i]) + if files[i].lower() == 'empty.png': + self.emptyfile = i + + self.editing = False + self.choosepic.currentIndexChanged.connect(self.choosePicChange) + self.choosepic.setCurrentIndex(i) + + def choosePicChange(self, ind): + self.filename = self.filenames[ind] + if exists(AOpath + 'evidence/' + self.filename): + self.evipicture.setPixmap(QtGui.QPixmap(AOpath + 'evidence/' + self.filename)) + else: + self.evipicture.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/evidence_selected.png')) + + def onSave(self): + name = encode_ao_str(self.eviname.text().toUtf8()) + desc = encode_ao_str(self.evidesc.toPlainText().toUtf8()) + + if self.editing: + self.gamegui.tcp.send('EE#' + str(self.edit_ind) + '#' + name + '#' + desc + '#' + self.filename + '#%') + else: + self.gamegui.tcp.send('PE#' + name + '#' + desc + '#' + self.filename + '#%') + + self.eviname.setText('') + self.evidesc.setText('') + evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png') + self.evipicture.setPixmap(evipic) + self.filename = 'empty.png' + self.editing = False + self.setWindowTitle('Add evidence') + self.choosepic.setCurrentIndex(self.emptyfile) + self.hide() + + def onCancel(self): + self.eviname.setText('') + self.evidesc.setText('') + evipic = QtGui.QPixmap(AOpath + 'evidence/empty.png') + self.evipicture.setPixmap(evipic) + self.filename = 'empty.png' + self.editing = False + self.setWindowTitle('Add evidence') + self.choosepic.setCurrentIndex(self.emptyfile) + self.hide() + + def EditEvidence(self, ind): + self.editing = True + self.edit_ind = ind + if self.gamegui.evidence[ind][2] not in self.filenames: + self.filenames.append(self.gamegui.evidence[ind][2]) + self.choosepic.addItem(self.gamegui.evidence[ind][2].split('.')[0]) + self.choosepic.setCurrentIndex(self.filenames.index(self.gamegui.evidence[ind][2])) + self.eviname.setText(self.gamegui.evidence[ind][0]) + self.evidesc.setText(self.gamegui.evidence[ind][1]) + self.setWindowTitle('Edit evidence') + self.show() + + +class EmoteButton(QtGui.QLabel): + + def __init__(self, gamewindow, x, y, id): + super(EmoteButton, self).__init__(gamewindow) + self.gamewindow = gamewindow + self.resize(40, 40) + self.move(x, y) + self.emoteid = id + + def paintEvent(self, event): + if self.gamewindow.mychar == -1: + return + + painter = QtGui.QPainter(self) + painter.setRenderHint(QtGui.QPainter.TextAntialiasing, False) + painter.setPen(QtGui.QColor(255, 255, 255)) + font = QtGui.QFont("Tahoma", 8) + font.setStyle(QtGui.QFont.StyleNormal) + font.setWeight(QtGui.QFont.Normal) + painter.setFont(font) + + if self.pixmap(): + if self.pixmap().isNull(): + painter.fillRect(0, 0, 39, 39, QtGui.QColor(0, 0, 0)) + painter.drawText(0, 0, str(self.emoteid)) + else: + painter.drawPixmap(0, 0, self.pixmap()) + else: + painter.fillRect(0, 0, 39, 39, QtGui.QColor(0, 0, 0)) + painter.drawText(1, 1, str(self.emoteid)) + + def mousePressEvent(self, event): + self.gamewindow.changeEmote(False, self.emoteid) + + +class BackEmoteButton(QtGui.QLabel): + + def __init__(self, gamewindow, x, y): + super(BackEmoteButton, self).__init__(gamewindow) + self.gamewindow = gamewindow + self.move(x, y) + self.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/arrow_left.png')) + self.show() + + def mousePressEvent(self, event): + self.gamewindow.current_emote_page -= 1 + self.gamewindow.set_emote_page() + + +class NextEmoteButton(QtGui.QLabel): + + def __init__(self, gamewindow, x, y): + super(NextEmoteButton, self).__init__(gamewindow) + self.gamewindow = gamewindow + self.move(x, y) + self.setPixmap(QtGui.QPixmap(AO2XPpath + 'themes/default/arrow_right.png')) + self.show() + + def mousePressEvent(self, event): + self.gamewindow.current_emote_page += 1 + self.gamewindow.set_emote_page() + + +class TCP_Thread(QtCore.QThread): + connectionError = QtCore.pyqtSignal(str, str, str) + MS_Chat = QtCore.pyqtSignal(list) + newChar = QtCore.pyqtSignal(str) + newBackground = QtCore.pyqtSignal(str) + IC_Log = QtCore.pyqtSignal(str) + OOC_Log = QtCore.pyqtSignal(str) + charSlots = QtCore.pyqtSignal() + showCharSelect = QtCore.pyqtSignal() + allEvidence = QtCore.pyqtSignal(list) + rainbowColor = QtCore.pyqtSignal(str) + + def __init__(self, parent): + super(TCP_Thread, self).__init__(parent) + self.parent = parent + + def run(self): + pingtimer = 150 + rainbow = 0 + sendtick = 0 + tempdata = "" + color = QtGui.QColor() + color.setHsv(rainbow, 255, 255) + while True: + if self.parent.disconnectnow: + self.parent.stopMusic() + self.parent.tcp.close() + self.quit() + return + pingtimer -= 1 + if pingtimer == 0: + pingbefore = time.time() + self.parent.tcp.send('CH#%') + pingtimer = 150 + + if self.parent.m_chatmessage[TEXT_COLOR] == "6": + color.setHsv(rainbow, 255, 255) + rainbow += 5 + if rainbow > 255: + rainbow = 0 + #self.parent.text.setStyleSheet('color: rgb(' + str(color.red()) + ', ' + str(color.green()) + ', ' + str(color.blue()) + ')') + self.rainbowColor.emit('color: rgb(' + str(color.red()) + ', ' + str(color.green()) + ', ' + str(color.blue()) + ')') + + if sendtick: + sendtick -= 1 + if self.parent.msgqueue and not sendtick: + self.parent.tcp.send(self.parent.msgqueue[0]) + sendtick = 4 + + error, total = self.parent.tcp.recv() + if error == -2: + continue + elif error == -1: + self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', "%s connection to server lost." % ("WebSocket" if self.parent.tcp.isWS else "TCP")) + self.parent.willDisconnect = True + self.quit() + return + + for network in total: + header = network[0] + #del network[-1] + if header == 'MS': + if len(network) < 15: + print '[warning]', 'malformed/incomplete MS#chat (IC chat) network message was received' + continue + + network[CHATMSG] = decode_ao_str(network[CHATMSG].decode('utf-8')) + self.MS_Chat.emit(network) + + elif header == 'MC': + music = decode_ao_str(network[1]) + charid = int(network[2]) + t = time.localtime() + if charid != -1: + try: + name = self.parent.charlist[charid][0] + except: + name = 'char id %d' % charid + + if len(network) > 3 and network[3]: + name += " ("+network[3].decode("utf-8")+")" + #self.parent.icLog.append('[%d:%.2d] %s changed the music to %s' % (t[3], t[4], name, music)) + self.IC_Log.emit('[%d:%.2d] %s changed the music to %s' % (t[3], t[4], name, music)) + else: + self.IC_Log.emit('[%d:%.2d] the music was changed to %s' % (t[3], t[4], music)) + self.parent.playMusic(music) + + elif header == 'BN': + self.newBackground.emit(network[1]) + + elif header == 'CT': + name = decode_ao_str(network[1].decode('utf-8')) + chatmsg = decode_ao_str(network[2].decode('utf-8').replace("\n", "
")) + #self.parent.ooclog.append('%s: %s' % (name, chatmsg)) + self.OOC_Log.emit("%s: %s" % (name, chatmsg)) + + elif header == 'PV': + self.parent.mychar = int(network[3]) + self.parent.charselect.hide() + self.newChar.emit(self.parent.charlist[self.parent.mychar][0]) + + elif header == 'LE': + del network[0] + self.allEvidence.emit([evi.split('&') for evi in network]) + + elif header == 'ZZ': + if self.parent.modcall: + audio.freehandle(self.parent.modcall) + self.parent.modcall = audio.loadhandle(0, "mod_call.wav", 0, 0, 0) + audio.sethandleattr(self.parent.modcall, BASS_ATTRIB_VOL, self.parent.soundslider.value() / 100.0) + audio.playhandle(self.parent.modcall, False) + + if len(network) > 1: + self.OOC_Log.emit('[MOD CALL] ' + network[1].replace("\n", "
") + '
') + else: + self.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)): + self.parent.charlist[i][1] = int(network[i]) + + self.charSlots.emit() + + elif header == 'RT': + testimony = network[1] + wtcefile = AOpath+"sounds/general/sfx-testimony2" + if self.parent.wtcesfx: + audio.freehandle(self.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 + 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.soundslider.value() / 100.0) + audio.playhandle(self.parent.wtcesfx, True) + self.parent.WTCEsignal.emit(testimony, variant) + + elif header == 'HP': + type = int(network[1]) + health = int(network[2]) + self.parent.healthbars.emit(type, health) + + elif header == 'KK': + reason = network[1] + self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'critical', 'Connection lost', 'You were kicked off the server. (%s)' % reason) + + elif header == 'KB': + reason = network[1] + self.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] + self.parent.emit(QtCore.SIGNAL('showMessage(QString, QString, QString)'), 'warning', '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"] + self.OOC_Log.emit("%s" % (statusStrings[status+1])) + + elif header == "CHECK": #ping + pingafter = time.time() + self.parent.gotPing.emit(int((pingafter - pingbefore)*1000)) + + elif header == 'DONE': + self.showCharSelect.emit() diff --git a/mainmenu.py b/mainmenu.py index 2f51ada..d1ec0b6 100644 --- a/mainmenu.py +++ b/mainmenu.py @@ -517,7 +517,7 @@ class AOServerInfo(QtCore.QThread): print self.webAO_bucket elif header == "ID": - self.tcp.send("ID#AO2XP#%s#%%" % GAME_VERSION[1:]) # need to send this to tsuserver3 servers in order to get feature list (FL) + self.tcp.send("ID#AO2XP#%s#%%" % "2.11.0") # need to send this to tsuserver3 servers in order to get feature list (FL) elif header == "FL": features = network[1:] diff --git a/quicksetup.py b/quicksetup.py index aa39f7a..9285774 100644 --- a/quicksetup.py +++ b/quicksetup.py @@ -100,6 +100,7 @@ if platform.system() == "Windows": print "installing pyqt4" pip_install('PyQt4-4.11.4-cp27-cp27m-win32.whl') + raw_input("Press Enter to continue...") elif platform.system() == "Darwin": print "installing pyobjc"