diff --git a/README.md b/README.md index c1e5336f4..bf66c9549 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,2 @@ -# Attorney Online - -![CI build](https://github.com/AttorneyOnline/AO2-Client/actions/workflows/build.yml/badge.svg?event=push) ![license](https://img.shields.io/github/license/AttorneyOnline/AO2-Client?color=blue) ![contributors](https://img.shields.io/github/contributors/AttorneyOnline/AO2-Client)
- -[Attorney Online](https://aceattorneyonline.com) is an online version of the world-renowned courtroom drama simulator that allows you to create and play out cases in an off-the-cuff format. - -**[Refer to the docs](https://github.com/AttorneyOnline/docs/blob/master/docs/index.md) for more information.** - -Linux users will need to install the system dependencies related to Qt. These are the commands to run on a terminal for some distributions: -* Ubuntu 22.04 LTS: -``` -$ sudo apt-get install qt5-base-dev libqt5websockets5 qt5-image-formats-plugins libqt5svg5 -``` -* Arch: -``` -$ sudo pacman -Syu qt5-base qt5-websockets qt5-imageformats qt5-svg -``` -* Fedora: -``` -$ sudo dnf install qt5-qtbase qt5-qtwebsockets qt5-qtimageformats qt5-qtsvg -``` - -## Credits - -This is a open-source remake of Attorney Online written by OmniTroid. The original Attorney Online client was written by FanatSors in Delphi. - -The logo (`logo.png` and `logo.ico`) was designed by Lucas Carbi. The characters depicted in the logo are owned by Capcom. - -### Project - -The project is dual-licensed; you are free to copy, modify and distribute AO2 under the GPLv3 or the MIT license. - -Copyright (c) 2016-2018 David "OmniTroid" Skoland - -Modifications copyright (c) 2017-2018 oldmud0 - -Case Café additions copyright (c) 2018 Cerapter - -Killing Fever Online additions copyright (c) 2019 Crystalwarrior - -### Qt - -This project uses Qt 5, which is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.txt) with [certain licensing restrictions and exceptions](https://www.qt.io/qt-licensing-terms/). To comply with licensing requirements for static linking, object code is available if you would like to relink with an alternative version of Qt, and the source code for Qt may be found at https://github.com/qt/qtbase, http://code.qt.io/cgit/, or at https://qt.io. - -Copyright (c) 2016 The Qt Company Ltd. - -### BASS - -This project depends on the BASS shared library. Get it here: http://www.un4seen.com/ - -Copyright (c) 1999-2016 Un4seen Developments Ltd. All rights reserved. +### Misairu +This is an open-source conversion of the Attorney Online 2 chat client into a standalone casemaking engine. See that repository for more technical information as this project builds up its own documentation over time. \ No newline at end of file diff --git a/include/aoapplication.h b/include/aoapplication.h index 8ef2a12d4..75ec40b00 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -85,25 +85,6 @@ class AOApplication : public QApplication { qint64 latency = 0; QString window_title; - /////////////////server metadata////////////////// - - bool yellow_text_supported = false; - bool prezoom_supported = false; - bool flipping_supported = false; - bool custom_objection_supported = false; - bool desk_mod_supported = false; - bool evidence_supported = false; - bool cccc_ic_supported = false; - bool arup_supported = false; - bool casing_alerts_supported = false; - bool modcall_reason_supported = false; - bool looping_sfx_supported = false; - bool additive_text_supported = false; - bool effects_supported = false; - bool y_offset_supported = false; - bool expanded_desk_mods_supported = false; - bool auth_packet_supported = false; - ///////////////loading info/////////////////// // client ID. Not useful, to be removed eventually @@ -157,7 +138,7 @@ class AOApplication : public QApplication { QString get_asset(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder=""); QString get_image(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="", bool static_image=false); QString get_sfx(QString p_sfx, QString p_misc="", QString p_character=""); - QString get_pos_path(const QString& pos, bool desk = false); + QPair get_pos_path(const QString& pos, bool desk = false); QString get_case_sensitive_path(QString p_file); QString get_real_path(const VPath &vpath, const QStringList &suffixes={""}); void invalidate_lookup_cache(); @@ -295,6 +276,14 @@ class AOApplication : public QApplication { // Returns whether the given pos is a judge position bool get_pos_is_judge(const QString &p_pos); + /** + * @brief Returns the duration of the transition animation between the two given positions, if it exists + */ + int get_pos_transition_duration(const QString &old_pos, const QString &new_pos); + + // Returns the name of p_char + QString get_char_name(QString p_char); + // Returns the total amount of emotes of p_char int get_emote_number(QString p_char); diff --git a/include/aolayer.h b/include/aolayer.h index 19dce38bb..3390028ba 100644 --- a/include/aolayer.h +++ b/include/aolayer.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include class AOApplication; class VPath; @@ -72,6 +74,12 @@ class AOLayer : public QLabel { // Stop the movie and clear all vectors void kill(); + // Start playback of the movie (if animated). + void play(); + + // Freeze the movie at the current frame. + void freeze(); + // Set the m_flipped variable to true/false void set_flipped(bool p_flipped) { m_flipped = p_flipped; } @@ -84,6 +92,9 @@ class AOLayer : public QLabel { // Move the label and center it void move_and_center(int ax, int ay); + // Returns the scaling factor + float get_scaling_factor(); + // This is somewhat pointless now as there's no "QMovie" object to resize, aka // no "combo" to speak of void combo_resize(int w, int h); @@ -91,10 +102,23 @@ class AOLayer : public QLabel { // Return the frame delay adjusted for speed int get_frame_delay(int delay); + /** + * @brief Returns the x offset to use to ensure proper centering in the viewport. + * This is used by courtroom transition code to know exactly where to put the characters at the start and end of the animation. + * @return The offset to center the pixmap in the viewport + */ + int get_centered_offset(); + // iterate through a list of paths and return the first entry that exists. if // none exist, return NULL (safe because we check again for existence later) QString find_image(QStringList p_list); + void fade(bool in, int duration); + + QPropertyAnimation* slide(int newcenter, int duration); + + void invert(); + protected: AOApplication *ao_app; QVector movie_frames; @@ -117,6 +141,8 @@ class AOLayer : public QLabel { int f_w = 0; int f_h = 0; + float scaling_factor = 0.0; + int frame = 0; int max_frames = 0; int last_max_frames = 0; @@ -127,20 +153,26 @@ class AOLayer : public QLabel { int duration = 0; - // Start playback of the movie (if animated). - void play(); - - // Freeze the movie at the current frame. - void freeze(); - // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a // provided QImage QPixmap get_pixmap(QImage image); // Set the movie's frame to provided pixmap void set_frame(QPixmap f_pixmap); + + // If set to anything other than -1, overrides center_pixmap to use it as a pixel position to center at + // Currently only used by background layers + int g_center = -1; + int last_center = -1; // g_center from the last image. + int centered_offset = 0; // Center the QLabel in the viewport based on the dimensions of f_pixmap void center_pixmap(QPixmap f_pixmap); + /*! + @brief Get the position to move us to, given the pixel X position of the point in the original image that we'd like to be centered. + + @return The position to move to. + */ + int get_pos_from_center(int f_center); private: // Populates the frame and delay vectors. @@ -161,13 +193,19 @@ protected slots: virtual void preanim_done(); void shfx_timer_done(); virtual void movie_ticker(); + virtual void fadeout_finished(); + virtual void fadein_finished(); }; class BackgroundLayer : public AOLayer { Q_OBJECT public: BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app); - void load_image(QString p_filename); + void load_image(QString p_filename, int center = -1); +signals: + void hide_void(); +protected: + void fadein_finished() override; // overridden to send the courtroom a signal to hide the void element }; class CharLayer : public AOLayer { diff --git a/include/courtroom.h b/include/courtroom.h index 65ef75af7..c162f72fe 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -24,7 +24,7 @@ #include "lobby.h" #include "scrolltext.h" #include "eventfilters.h" -#include "aoemotepreview.h" +#include "misc_functions.h" #include #include @@ -187,14 +187,11 @@ class Courtroom : public QMainWindow { // sets the local mute list based on characters available on the server void set_mute_list(); - // Sets the local pair list based on the characters available on the server. - void set_pair_list(); - // sets desk and bg based on pos in chatmessage void set_scene(bool show_desk, QString f_side); - // sets ui_vp_player_char according to SELF_OFFSET, only a function bc it's used with desk_mod 4 and 5 - void set_self_offset(const QString& p_list); + // sets p_layer according to SELF_OFFSET, only a function bc it's used with desk_mod 4 and 5 + void set_self_offset(const QString& p_list, AOLayer* p_layer); // takes in serverD-formatted IP list as prints a converted version to server // OOC admittedly poorly named @@ -264,12 +261,12 @@ class Courtroom : public QMainWindow { // Handle the stuff that comes when the character appears on screen and starts animating (preanims etc.) void handle_ic_message(); + // Start the logic for doing a courtroom pan transition + void do_transition(QString desk_mod, QString old_pos, QString new_pos); + // Display the character. void display_character(); - // Display the character's pair if present. - void display_pair_character(QString other_charid, QString other_offset); - // Handle the emote modifier value and proceed through the logic accordingly. void handle_emote_mod(int emote_mod, bool p_immediate); @@ -365,6 +362,9 @@ class Courtroom : public QMainWindow { QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; + QParallelAnimationGroup *transition_animation_group = new QParallelAnimationGroup; + + bool next_character_is_not_special = false; // If true, write the // next character as it is. @@ -383,9 +383,6 @@ class Courtroom : public QMainWindow { // The vertical offset this user has given. int char_vert_offset = 0; - // 0 = in front, 1 = behind - int pair_order = 0; - QVector char_list; QVector evidence_list; QVector music_list; @@ -496,6 +493,11 @@ class Courtroom : public QMainWindow { static const int MS_MAXIMUM = 30; QString m_chatmessage[MS_MAXIMUM]; + /** + * @brief The amount of time to wait at the start and end of transition animations + */ + static const int TRANSITION_BOOKEND_DELAY = 300; + QString previous_ic_message = ""; QString additive_previous = ""; @@ -626,6 +628,11 @@ class Courtroom : public QMainWindow { QString current_background = "default"; QString current_side = ""; + // used for courtroom transition logic + QString last_side = ""; + int last_offset = 0; + int last_v_offset = 0; + QString last_music_search = ""; QString last_area_search = ""; @@ -647,6 +654,7 @@ class Courtroom : public QMainWindow { AOImage *ui_background; QWidget *ui_viewport; + QLabel *ui_vp_void; BackgroundLayer *ui_vp_background; SplashLayer *ui_vp_speedlines; CharLayer *ui_vp_player_char; @@ -679,13 +687,9 @@ class Courtroom : public QMainWindow { static const int max_clocks = 5; AOClockLabel *ui_clock[max_clocks]; - AOButton *ui_pair_button; - QListWidget *ui_pair_list; QSpinBox *ui_pair_offset_spinbox; QSpinBox *ui_pair_vert_offset_spinbox; - QComboBox *ui_pair_order_dropdown; - QLineEdit *ui_ic_chat_message; AOLineEditFilter *ui_ic_chat_message_filter; QLineEdit *ui_ic_chat_name; @@ -840,6 +844,7 @@ public slots: void objection_done(); void preanim_done(); void do_screenshake(); + void on_transition_finish(); void do_flash(); void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); @@ -858,7 +863,6 @@ private slots: void chat_tick(); void on_mute_list_clicked(QModelIndex p_index); - void on_pair_list_clicked(QModelIndex p_index); void on_chat_return_pressed(); @@ -938,8 +942,6 @@ private slots: void on_screenshake_clicked(); void on_mute_clicked(); - void on_pair_clicked(); - void on_pair_order_dropdown_changed(int p_index); void on_defense_minus_clicked(); void on_defense_plus_clicked(); @@ -1015,8 +1017,8 @@ private slots: // Proceed to parse the oldest chatmessage and remove it from the stack void chatmessage_dequeue(); - void preview_emote(QString emote); - void update_emote_preview(); + // After attempting to play a transition animation, clean up the viewport objects for everyone else and continue the IC processing callstack + void post_transition_cleanup(); }; #endif // COURTROOM_H diff --git a/include/datatypes.h b/include/datatypes.h index 3a82efffe..46eb37045 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -97,7 +97,7 @@ enum CHAT_MESSAGE { REALIZATION, TEXT_COLOR, SHOWNAME, - OTHER_CHARID, + TRANSITION, // formerly OTHER_CHARID OTHER_NAME, OTHER_EMOTE, SELF_OFFSET, diff --git a/include/misc_functions.h b/include/misc_functions.h index 5287bee83..e5b66452e 100644 --- a/include/misc_functions.h +++ b/include/misc_functions.h @@ -2,7 +2,8 @@ #define MISC_FUNCTIONS_H #include -#include +#include +#include void delay(int p_milliseconds); diff --git a/Attorney_Online.pro b/misairu.pro similarity index 88% rename from Attorney_Online.pro rename to misairu.pro index e2bec3952..068e5eadc 100644 --- a/Attorney_Online.pro +++ b/misairu.pro @@ -1,9 +1,9 @@ QT += core gui widgets network websockets uitools -TARGET = Attorney_Online +TARGET = kenji TEMPLATE = app -VERSION = 2.10.1.0 +VERSION = 0.1.0.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin @@ -24,6 +24,9 @@ QMAKE_LFLAGS += -Wl,-rpath,"'\$$ORIGIN/lib'" # Uncomment for verbose animation logging # DEFINES += DEBUG_MOVIE +# Uncomment for transition debug features +# DEFINES += DEBUG_TRANSITIONS + # Uncomment for building with debug symbols # CONFIG += debug @@ -36,7 +39,7 @@ contains(DEFINES, DISCORD) { mac:LIBS += -ldiscord-rpc } -# As of 2.8.5, BASS and BASSOPUS are required for all platforms. Qt Multimedia +# As of Attorney Online 2.8.5, BASS and BASSOPUS are required for all platforms. Qt Multimedia # is no longer an option due to outdated code and lack of versatility. # Download at un4seen.com and place the DLLs in the "lib" and "bin" folders. DEFINES += BASSAUDIO @@ -62,8 +65,8 @@ TRANSLATIONS = resource/translations/ao_en.ts \ resource/translations/ao_it.ts \ ressource/ui/ -win32:RC_ICONS = resource/logo_ao2.ico -macx:ICON = resource/logo_ao2.icns +win32:RC_ICONS = resource/logo_kenji.ico +macx:ICON = android:QT += androidextras diff --git a/resource/logo.iconset/icon_1024x1024.png b/resource/logo.iconset/icon_1024x1024.png deleted file mode 100644 index 97c96a4a8..000000000 Binary files a/resource/logo.iconset/icon_1024x1024.png and /dev/null differ diff --git a/resource/logo.iconset/icon_128x128.png b/resource/logo.iconset/icon_128x128.png deleted file mode 100644 index b08cc076c..000000000 Binary files a/resource/logo.iconset/icon_128x128.png and /dev/null differ diff --git a/resource/logo.iconset/icon_128x128@2x.png b/resource/logo.iconset/icon_128x128@2x.png deleted file mode 100644 index 355253d37..000000000 Binary files a/resource/logo.iconset/icon_128x128@2x.png and /dev/null differ diff --git a/resource/logo.iconset/icon_16x16.png b/resource/logo.iconset/icon_16x16.png deleted file mode 100644 index e0e088dcf..000000000 Binary files a/resource/logo.iconset/icon_16x16.png and /dev/null differ diff --git a/resource/logo.iconset/icon_16x16@2x.png b/resource/logo.iconset/icon_16x16@2x.png deleted file mode 100644 index 01bab8632..000000000 Binary files a/resource/logo.iconset/icon_16x16@2x.png and /dev/null differ diff --git a/resource/logo.iconset/icon_256x256.png b/resource/logo.iconset/icon_256x256.png deleted file mode 100644 index 355253d37..000000000 Binary files a/resource/logo.iconset/icon_256x256.png and /dev/null differ diff --git a/resource/logo.iconset/icon_256x256@2x.png b/resource/logo.iconset/icon_256x256@2x.png deleted file mode 100644 index 4191c2f82..000000000 Binary files a/resource/logo.iconset/icon_256x256@2x.png and /dev/null differ diff --git a/resource/logo.iconset/icon_32x32.png b/resource/logo.iconset/icon_32x32.png deleted file mode 100644 index 01bab8632..000000000 Binary files a/resource/logo.iconset/icon_32x32.png and /dev/null differ diff --git a/resource/logo.iconset/icon_32x32@2x.png b/resource/logo.iconset/icon_32x32@2x.png deleted file mode 100644 index c4e28ad20..000000000 Binary files a/resource/logo.iconset/icon_32x32@2x.png and /dev/null differ diff --git a/resource/logo.iconset/icon_512x512.png b/resource/logo.iconset/icon_512x512.png deleted file mode 100644 index 4191c2f82..000000000 Binary files a/resource/logo.iconset/icon_512x512.png and /dev/null differ diff --git a/resource/logo.iconset/icon_512x512@2x.png b/resource/logo.iconset/icon_512x512@2x.png deleted file mode 100644 index 97c96a4a8..000000000 Binary files a/resource/logo.iconset/icon_512x512@2x.png and /dev/null differ diff --git a/resource/logo.iconset/icon_64x64.png b/resource/logo.iconset/icon_64x64.png deleted file mode 100644 index c4e28ad20..000000000 Binary files a/resource/logo.iconset/icon_64x64.png and /dev/null differ diff --git a/resource/logo.iconset/icon_64x64@2x.png b/resource/logo.iconset/icon_64x64@2x.png deleted file mode 100644 index b08cc076c..000000000 Binary files a/resource/logo.iconset/icon_64x64@2x.png and /dev/null differ diff --git a/resource/logo_ao2.icns b/resource/logo_ao2.icns deleted file mode 100644 index fb2456c80..000000000 Binary files a/resource/logo_ao2.icns and /dev/null differ diff --git a/resource/logo_ao2.ico b/resource/logo_ao2.ico deleted file mode 100644 index b40e7866a..000000000 Binary files a/resource/logo_ao2.ico and /dev/null differ diff --git a/resource/logo_ao2.png b/resource/logo_ao2.png deleted file mode 100644 index f53fe30cf..000000000 Binary files a/resource/logo_ao2.png and /dev/null differ diff --git a/resource/logo_ao2.rc b/resource/logo_ao2.rc deleted file mode 100644 index ed785de86..000000000 --- a/resource/logo_ao2.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON "logo_ao2.ico" diff --git a/resource/logo_kenji.ico b/resource/logo_kenji.ico new file mode 100644 index 000000000..05bf02953 Binary files /dev/null and b/resource/logo_kenji.ico differ diff --git a/resource/logo_kenji.png b/resource/logo_kenji.png new file mode 100644 index 000000000..4330f9b11 Binary files /dev/null and b/resource/logo_kenji.png differ diff --git a/resource/logo_kenji.rc b/resource/logo_kenji.rc new file mode 100644 index 000000000..e3b9fd546 --- /dev/null +++ b/resource/logo_kenji.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON "logo_kenji.ico" diff --git a/resource/logo_kfo.ico b/resource/logo_kfo.ico deleted file mode 100644 index 3c68adff5..000000000 Binary files a/resource/logo_kfo.ico and /dev/null differ diff --git a/resource/logo_kfo.png b/resource/logo_kfo.png deleted file mode 100644 index d8001233a..000000000 Binary files a/resource/logo_kfo.png and /dev/null differ diff --git a/resources.qrc b/resources.qrc index 2f8d264ae..bbbe6629f 100644 --- a/resources.qrc +++ b/resources.qrc @@ -1,7 +1,6 @@ resource/fonts/Ace-Attorney.ttf - resource/logo_ao2.png resource/translations/ao_de.qm resource/translations/ao_en.qm resource/translations/ao_es.qm diff --git a/src/aolayer.cpp b/src/aolayer.cpp index f9b01d3bd..927f9d80d 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -84,6 +84,7 @@ QPixmap AOLayer::get_pixmap(QImage image) f_pixmap = QPixmap::fromImage(image); // auto aspect_ratio = Qt::KeepAspectRatio; if (!f_pixmap.isNull()) { + scaling_factor = float(f_h) / float(f_pixmap.height()); if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. transform_mode = Qt::SmoothTransformation; if (stretch) @@ -102,14 +103,38 @@ void AOLayer::set_frame(QPixmap f_pixmap) } void AOLayer::center_pixmap(QPixmap f_pixmap) { - QLabel::move( - x + (f_w - f_pixmap.width()) / 2, - y + (f_h - f_pixmap.height())); // Always center horizontally, always put - // at the bottom vertically - if (masked) - this->setMask( - QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w, - f_h)); // make sure we don't escape the area we've been given + if (g_center == -1) { + centered_offset = (f_w - f_pixmap.width()) / 2; + QLabel::move( + x + (f_w - f_pixmap.width()) / 2, + y + (f_h - f_pixmap.height())); // Always center horizontally, always put + // at the bottom vertically + } + else { + QLabel::move(get_pos_from_center(g_center), y + (f_h - f_pixmap.height())); + } + if (masked) { + if (g_center == -1) { + this->setMask( + QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w, + f_h)); // make sure we don't escape the area we've been given + } + else { + int center_scaled = int(float(g_center) * scaling_factor); + this->setMask(QRegion((f_pixmap.width() - center_scaled) / 2, (f_pixmap.height() - f_h) / 2, f_w, f_h)); + } + } +} + +int AOLayer::get_centered_offset() { + return centered_offset; +} + +int AOLayer::get_pos_from_center(int f_center) { + int center_scaled = int(float(f_center) * scaling_factor); + int f_pos = x + (center_scaled - (f_w / 2)) * -1; + qDebug() << "centering image at center" << f_center << "final position" << f_pos; + return f_pos; } void AOLayer::combo_resize(int w, int h) @@ -142,8 +167,11 @@ void AOLayer::move_and_center(int ax, int ay) center_pixmap(movie_frames[0]); // just use the first frame since dimensions are all that matter } -void BackgroundLayer::load_image(QString p_filename) +float AOLayer::get_scaling_factor() { return scaling_factor; } + +void BackgroundLayer::load_image(QString p_filename, int p_center) { + g_center = p_center; play_once = false; cull_image = false; VPath design_path = ao_app->get_background_path("design.ini"); @@ -155,7 +183,7 @@ void BackgroundLayer::load_image(QString p_filename) #endif QString final_path = ao_app->get_image_suffix(ao_app->get_background_path(p_filename)); - if (final_path == last_path) { + if (final_path == last_path && g_center == last_center) { // Don't restart background if background is unchanged return; } @@ -303,7 +331,7 @@ void AOLayer::start_playback(QString p_image) force_continuous = true; } - if (((last_path == p_image) && (!force_continuous)) || p_image == "") + if (((last_path == p_image) && (!force_continuous) && (g_center == last_center)) || p_image == "") return; #ifdef DEBUG_MOVIE @@ -343,6 +371,7 @@ void AOLayer::start_playback(QString p_image) frame_loader = QtConcurrent::run(thread_pool, &AOLayer::populate_vectors, this); #endif last_path = p_image; + last_center = g_center; while (movie_frames.size() <= frame) // if we haven't loaded the frame we need yet frameAdded.wait(&mutex); // wait for the frame loader to add another frame, then check again this->set_frame(movie_frames[frame]); @@ -625,3 +654,41 @@ void AOLayer::shfx_timer_done() // signal connected to courtroom object, let it figure out what to do emit done(); } + +void AOLayer::invert() { + const QPixmap &pixmap = this->pixmap(Qt::ReturnByValue); + QImage* image = new QImage(pixmap.toImage()); + image->invertPixels(QImage::InvertRgb); + this->setPixmap(QPixmap::fromImage(*image)); +} + +void AOLayer::fade(bool in, int duration) +{ + QGraphicsOpacityEffect* fade = new QGraphicsOpacityEffect(this); + this->setGraphicsEffect(fade); + QPropertyAnimation* fade_anim = new QPropertyAnimation(fade, "opacity"); + fade_anim->setDuration(duration); + fade_anim->setStartValue(in ? 0 : 1); + fade_anim->setEndValue(in ? 1 : 0); + fade_anim->setEasingCurve(QEasingCurve::Linear); + fade_anim->start(QPropertyAnimation::DeleteWhenStopped); + connect(fade_anim, SIGNAL(finished()), this, SLOT(in?fadein_finished():fadeout_finished())); + +} + +QPropertyAnimation* AOLayer::slide(int newcenter, int duration) { + QPropertyAnimation* slide_anim = new QPropertyAnimation(this, "pos"); + slide_anim->setDuration(duration); + slide_anim->setStartValue(this->pos().x()); + slide_anim->setEndValue(get_pos_from_center(newcenter)); + slide_anim->setEasingCurve(QEasingCurve::Linear); + return slide_anim; +} + + +void AOLayer::fadeout_finished() {} + +void AOLayer::fadein_finished() {} + +void BackgroundLayer::fadein_finished() {emit hide_void();} + diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 65c5e1a30..7af201038 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -49,8 +49,12 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_viewport = new QWidget(this); ui_viewport->setObjectName("ui_viewport"); + ui_vp_void = new QLabel(ui_viewport); + ui_vp_void->setStyleSheet("QLabel {background-color:black}"); + ui_vp_void->hide(); ui_vp_background = new BackgroundLayer(ui_viewport, ao_app); ui_vp_background->setObjectName("ui_vp_background"); + ui_vp_background->masked = false; ui_vp_speedlines = new SplashLayer(ui_viewport, ao_app); ui_vp_speedlines->setObjectName("ui_vp_speedlines"); ui_vp_speedlines->stretch = true; @@ -63,6 +67,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_sideplayer_char->hide(); ui_vp_desk = new BackgroundLayer(ui_viewport, ao_app); ui_vp_desk->setObjectName("ui_vp_desk"); + ui_vp_desk->masked = false; ui_vp_effect = new EffectLayer(this, ao_app); ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -301,7 +306,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_flip = new QCheckBox(this); ui_flip->setText(tr("Flip")); - ui_flip->hide(); ui_flip->setObjectName("ui_flip"); ui_guard = new QCheckBox(this); @@ -311,7 +315,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_additive = new QCheckBox(this); ui_additive->setText(tr("Additive")); - ui_additive->hide(); ui_additive->setObjectName("ui_additive"); ui_showname_enable = new QCheckBox(this); @@ -321,7 +324,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_immediate = new QCheckBox(this); ui_immediate->setText(tr("Immediate")); - ui_immediate->hide(); ui_immediate->setObjectName("ui_immediate"); ui_custom_objection = new AOButton(this, ao_app); @@ -374,9 +376,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_mute_list = new QListWidget(this); ui_mute_list->setObjectName("ui_mute_list"); - ui_pair_list = new QListWidget(this); - ui_pair_list->setObjectName("ui_pair_list"); - ui_pair_offset_spinbox = new QSpinBox(this); ui_pair_offset_spinbox->setRange(-100, 100); ui_pair_offset_spinbox->setSuffix("% x"); @@ -387,14 +386,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pair_vert_offset_spinbox->setSuffix("% y"); ui_pair_vert_offset_spinbox->setObjectName("ui_pair_vert_offset_spinbox"); - ui_pair_order_dropdown = new QComboBox(this); - ui_pair_order_dropdown->addItem(tr("To front")); - ui_pair_order_dropdown->addItem(tr("To behind")); - ui_pair_order_dropdown->setObjectName("ui_pair_order_dropdown"); - - ui_pair_button = new AOButton(this, ao_app); - ui_pair_button->setObjectName("ui_pair_button"); - ui_evidence_button = new AOButton(this, ao_app); ui_evidence_button->setContextMenuPolicy(Qt::CustomContextMenu); ui_evidence_button->setObjectName("ui_evidence_button"); @@ -416,6 +407,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_vp_player_char, &CharLayer::flash, this, &Courtroom::do_flash); connect(ui_vp_player_char, &CharLayer::play_sfx, this, &Courtroom::play_char_sfx); + connect(ui_vp_background, SIGNAL(hide_void()), ui_vp_void, SLOT(hide())); connect(text_delay_timer, &QTimer::timeout, this, &Courtroom::start_chat_ticking); @@ -543,15 +535,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_showname_enable, &AOButton::clicked, this, &Courtroom::on_showname_enable_clicked); - connect(ui_pair_button, &AOButton::clicked, this, &Courtroom::on_pair_clicked); - connect(ui_pair_list, &QListWidget::clicked, this, - &Courtroom::on_pair_list_clicked); connect(ui_pair_offset_spinbox, QOverload::of(&QSpinBox::valueChanged), this, &Courtroom::on_pair_offset_changed); connect(ui_pair_vert_offset_spinbox, QOverload::of(&QSpinBox::valueChanged), this, &Courtroom::on_pair_vert_offset_changed); - connect(ui_pair_order_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, - &Courtroom::on_pair_order_dropdown_changed); connect(ui_evidence_button, &AOButton::clicked, this, &Courtroom::on_evidence_button_clicked); @@ -563,6 +550,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_vp_evidence_display, &AOEvidenceDisplay::show_evidence_details, this, &Courtroom::show_evidence); + connect(transition_animation_group, &QParallelAnimationGroup::finished, this, &Courtroom::on_transition_finish); + set_widgets(); set_char_select(); @@ -641,20 +630,6 @@ void Courtroom::set_mute_list() } } -void Courtroom::set_pair_list() -{ - QStringList sorted_pair_list; - - for (const char_type &i_char : qAsConst(char_list)) - sorted_pair_list.append(i_char.name); - - sorted_pair_list.sort(); - - for (const QString &i_name : sorted_pair_list) { - ui_pair_list->addItem(i_name); - } -} - void Courtroom::set_widgets() { QString filename = "courtroom_design.ini"; @@ -665,20 +640,11 @@ void Courtroom::set_widgets() // If there is a point to it, show all CCCC features. // We also do this this soon so that set_size_and_pos can hide them all later, // if needed. - if (ao_app->cccc_ic_supported) { - ui_pair_button->show(); - ui_immediate->show(); - ui_showname_enable->show(); - ui_ic_chat_name->show(); - ui_ic_chat_name->setEnabled(true); - } - else { - ui_pair_button->hide(); - ui_immediate->hide(); - ui_showname_enable->hide(); - ui_ic_chat_name->hide(); - ui_ic_chat_name->setEnabled(false); - } + ui_immediate->show(); + ui_showname_enable->show(); + ui_ic_chat_name->show(); + ui_ic_chat_name->setEnabled(true); + ui_announce_casing->show(); // We also show the non-server-dependent client additions. // Once again, if the theme can't display it, set_move_and_pos will catch @@ -688,6 +654,8 @@ void Courtroom::set_widgets() // make the BG's reload ui_vp_background->kill(); ui_vp_desk->kill(); + ui_vp_void->move(0, 0); + ui_vp_void->resize(ui_viewport->width(), ui_viewport->height()); ui_vp_background->move_and_center(0, 0); ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -758,34 +726,18 @@ void Courtroom::set_widgets() set_size_and_pos(ui_mute_list, "mute_list"); ui_mute_list->hide(); - set_size_and_pos(ui_pair_list, "pair_list"); - ui_pair_list->hide(); - ui_pair_list->setToolTip(tr("Select a character you wish to pair with.")); - set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox"); - ui_pair_offset_spinbox->hide(); ui_pair_offset_spinbox->setToolTip( tr("Change the horizontal percentage offset of your character's position " "from the " "center of the screen.")); set_size_and_pos(ui_pair_vert_offset_spinbox, "pair_vert_offset_spinbox"); - ui_pair_vert_offset_spinbox->hide(); ui_pair_vert_offset_spinbox->setToolTip( tr("Change the vertical percentage offset of your character's position " "from the " "center of the screen.")); - ui_pair_order_dropdown->hide(); - set_size_and_pos(ui_pair_order_dropdown, "pair_order_dropdown"); - ui_pair_order_dropdown->setToolTip( - tr("Change the order of appearance for your character.")); - - set_size_and_pos(ui_pair_button, "pair_button"); - ui_pair_button->set_image("pair_button"); - ui_pair_button->setToolTip( - tr("Display the list of characters to pair with.")); - set_size_and_pos(ui_area_list, "music_list"); ui_area_list->header()->setMinimumSectionSize(ui_area_list->width()); @@ -1306,7 +1258,6 @@ void Courtroom::done_received() } set_mute_list(); - set_pair_list(); show(); @@ -1341,7 +1292,8 @@ void Courtroom::set_background(QString p_background, bool display) } } for (const QString &pos : ao_app->read_design_ini("positions", ao_app->get_background_path("design.ini")).split(",")) { - if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(pos)))) { + QString real_pos = pos.split(":")[0]; + if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(real_pos)))) { pos_list.append(pos); } } @@ -1428,7 +1380,7 @@ void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) for (int n = 0; n < pos_dropdown_list.size(); ++n) { QString pos = pos_dropdown_list.at(n); ui_pos_dropdown->addItem(pos); - QPixmap image = QPixmap(ao_app->get_image_suffix(ao_app->get_background_path(ao_app->get_pos_path(pos)))); + QPixmap image = QPixmap(ao_app->get_image_suffix(ao_app->get_background_path(ao_app->get_pos_path(pos).first))); if (!image.isNull()) { image = image.scaledToHeight(ui_pos_dropdown->iconSize().height()); } @@ -1502,42 +1454,19 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) ui_custom_objection->show(); QString custom_name = ao_app->read_char_ini(f_char, "custom_name", "Shouts"); QAction *action; - if (custom_name != "") + if (custom_name != "") { + custom_objection.name = custom_name; action = custom_obj_menu->addAction(custom_name); - else - action = custom_obj_menu->addAction("Default"); - custom_obj_menu->setDefaultAction(action); - objection_custom = ""; - } - QString custom_objection_dir = ao_app->get_real_path( - ao_app->get_character_path(current_char, "custom_objections")); - if (dir_exists(custom_objection_dir)) { - ui_custom_objection->show(); - QDir directory(custom_objection_dir); - QStringList custom_obj = directory.entryList(QStringList() << "*.png" - << "*.gif" - << "*.apng" - << "*.webp", - QDir::Files); - for (const QString &filename : custom_obj) { - CustomObjection custom_objection; - custom_objection.filename = filename; - QString custom_name = ao_app->read_char_ini(f_char, filename.left(filename.lastIndexOf(".")) + "_name", "Shouts"); - QAction *action; - if (custom_name != "") { - custom_objection.name = custom_name; - action = custom_obj_menu->addAction(custom_name); - } - else { - custom_objection.name = filename.left(filename.lastIndexOf(".")); - action = custom_obj_menu->addAction(custom_objection.name); - } - if (custom_obj_menu->defaultAction() == nullptr) { - custom_obj_menu->setDefaultAction(action); - objection_custom = custom_objection.filename; - } - custom_objections_list.append(custom_objection); } + else { + custom_objection.name = filename.left(filename.lastIndexOf(".")); + action = custom_obj_menu->addAction(custom_objection.name); + } + if (custom_obj_menu->defaultAction() == nullptr) { + custom_obj_menu->setDefaultAction(action); + objection_custom = custom_objection.filename; + } + custom_objections_list.append(custom_objection); } } @@ -1557,16 +1486,6 @@ void Courtroom::enter_courtroom() { set_evidence_page(); - if (ao_app->flipping_supported) - ui_flip->show(); - else - ui_flip->hide(); - - if (ao_app->additive_text_supported) - ui_additive->show(); - else - ui_additive->hide(); - list_music(); list_areas(); @@ -1669,26 +1588,23 @@ void Courtroom::list_areas() QString i_area = ""; i_area.append(area_list.at(n_area)); - if (ao_app->arup_supported) { - i_area.append("\n "); + i_area.append("\n "); + i_area.append(arup_statuses.at(n_area)); - i_area.append(arup_statuses.at(n_area)); - - if (arup_cms.at(n_area) != "FREE") { - i_area.append(" | CM: "); - i_area.append(arup_cms.at(n_area)); - } - - i_area.append("\n "); + if (arup_cms.at(n_area) != "FREE") { + i_area.append(" | CM: "); + i_area.append(arup_cms.at(n_area)); + } - if (arup_players.at(n_area) != -1) { - i_area.append(QString::number(arup_players.at(n_area))); - i_area.append(" users | "); - } + i_area.append("\n "); - i_area.append(arup_locks.at(n_area)); + if (arup_players.at(n_area) != -1) { + i_area.append(QString::number(arup_players.at(n_area))); + i_area.append(" users | "); } + i_area.append(arup_locks.at(n_area)); + QTreeWidgetItem *treeItem = ui_area_list->topLevelItem(n_area); if (treeItem == nullptr) { @@ -1697,27 +1613,23 @@ void Courtroom::list_areas() treeItem->setText(0, area_list.at(n_area)); treeItem->setText(1, i_area); - if (ao_app->arup_supported) { - // Coloring logic here. - treeItem->setBackground(1, free_brush); - if (arup_locks.at(n_area) == "LOCKED") { - treeItem->setBackground(1, locked_brush); - } - else { - if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") - treeItem->setBackground(1, lfp_brush); - else if (arup_statuses.at(n_area) == "CASING") - treeItem->setBackground(1, casing_brush); - else if (arup_statuses.at(n_area) == "RECESS") - treeItem->setBackground(1, recess_brush); - else if (arup_statuses.at(n_area) == "RP") - treeItem->setBackground(1, rp_brush); - else if (arup_statuses.at(n_area) == "GAMING") - treeItem->setBackground(1, gaming_brush); - } + // Coloring logic here. + // TODO: This whole area status system is unnecessarily hardcoded + treeItem->setBackground(1, free_brush); + if (arup_locks.at(n_area) == "LOCKED") { + treeItem->setBackground(1, locked_brush); } else { - treeItem->setBackground(1, free_brush); + if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") + treeItem->setBackground(1, lfp_brush); + else if (arup_statuses.at(n_area) == "CASING") + treeItem->setBackground(1, casing_brush); + else if (arup_statuses.at(n_area) == "RECESS") + treeItem->setBackground(1, recess_brush); + else if (arup_statuses.at(n_area) == "RP") + treeItem->setBackground(1, rp_brush); + else if (arup_statuses.at(n_area) == "GAMING") + treeItem->setBackground(1, gaming_brush); } ++n_listed_areas; @@ -1768,10 +1680,6 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini") .name(); - if (!ao_app->auth_packet_supported && p_message == "Logged in as a moderator.") { - // Emulate successful authentication - on_authentication_state_received(1); - } ui_server_chatlog->append_chatmessage(p_name, p_message, color); @@ -1838,17 +1746,13 @@ void Courtroom::on_chat_return_pressed() int f_desk_mod = DESK_SHOW; - if (ao_app->desk_mod_supported) { - f_desk_mod = ao_app->get_desk_mod(current_char, current_emote); - if (!ao_app->expanded_desk_mods_supported) { - if (f_desk_mod == DESK_PRE_ONLY_EX || f_desk_mod == DESK_PRE_ONLY) - f_desk_mod = DESK_HIDE; - else if (f_desk_mod == DESK_EMOTE_ONLY_EX || f_desk_mod == DESK_EMOTE_ONLY) - f_desk_mod = DESK_SHOW; - } - if (f_desk_mod == -1) - f_desk_mod = DESK_SHOW; - } + f_desk_mod = ao_app->get_desk_mod(current_char, current_emote); + if (f_desk_mod == DESK_PRE_ONLY_EX || f_desk_mod == DESK_PRE_ONLY) + f_desk_mod = DESK_HIDE; + else if (f_desk_mod == DESK_EMOTE_ONLY_EX || f_desk_mod == DESK_EMOTE_ONLY) + f_desk_mod = DESK_SHOW; + if (f_desk_mod == -1) + f_desk_mod = DESK_SHOW; packet_contents.append(QString::number(f_desk_mod)); @@ -1877,7 +1781,7 @@ void Courtroom::on_chat_return_pressed() f_emote_mod = PREANIM; } // Turn zoom into preanim zoom - else if (f_emote_mod == ZOOM && ao_app->prezoom_supported) { + else if (f_emote_mod == ZOOM) { f_emote_mod = PREANIM_ZOOM; } // Play the sfx @@ -1933,8 +1837,7 @@ void Courtroom::on_chat_return_pressed() QString f_obj_state; - if ((objection_state == 4 && !ao_app->custom_objection_supported) || - (objection_state < 0)) + if (objection_state < 0) f_obj_state = "0"; else if (objection_custom != "" && objection_state == 4) { f_obj_state = QString::number(objection_state) + "&" + @@ -1958,15 +1861,10 @@ void Courtroom::on_chat_return_pressed() packet_contents.append("0"); QString f_flip; - - if (ao_app->flipping_supported) { - if (ui_flip->isChecked()) - f_flip = "1"; - else - f_flip = "0"; - } + if (ui_flip->isChecked()) + f_flip = "1"; else - f_flip = QString::number(m_cid); + f_flip = "0"; packet_contents.append(f_flip); @@ -1983,98 +1881,83 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(f_text_color); - // If the server we're on supports CCCC stuff, we should use it! - if (ao_app->cccc_ic_supported) { - // If there is a showname entered, use that -- else, just send an empty - // packet-part. - if (!ui_ic_chat_name->text().isEmpty()) { - packet_contents.append(ui_ic_chat_name->text()); - } - else { - packet_contents.append(""); - } - - // Similarly, we send over whom we're paired with, unless we have chosen - // ourselves. Or a charid of -1 or lower, through some means. - if (other_charid > -1 && other_charid != m_cid) { - QString packet = QString::number(other_charid); - if (ao_app->effects_supported) // Only servers with effects enabled will - // support pair reordering - packet += "^" + QString::number(pair_order); - packet_contents.append(packet); - } - else { - packet_contents.append("-1"); - } - // Send the offset as it's gonna be used regardless - if(ao_app->y_offset_supported) - packet_contents.append(QString::number(char_offset) + "&" + QString::number(char_vert_offset)); - else - packet_contents.append(QString::number(char_offset)); + // If there is a showname entered, use that -- else, just send an empty + // packet-part. + if (!ui_ic_chat_name->text().isEmpty()) { + packet_contents.append(ui_ic_chat_name->text()); + } + else { + packet_contents.append(""); + } + // Similarly, we send over whom we're paired with, unless we have chosen + // ourselves. Or a charid of -1 or lower, through some means. + // Also send over the pairing order. + // TODO: REWORK THIS FOR TRANSITIONS + if (other_charid > -1 && other_charid != m_cid) { + QString packet = QString::number(other_charid) + "^" + QString::number(0); + packet_contents.append(packet); + } + else { + packet_contents.append("-1"); + } + packet_contents.append(QString::number(char_offset) + "&" + QString::number(char_vert_offset)); - // Finally, we send over if we want our pres to not interrupt. - if (ui_immediate->isChecked() && ui_pre->isChecked()) { - packet_contents.append("1"); - } - else { - packet_contents.append("0"); - } + // Finally, we send over if we want our text to process immediately, instead of after the preanimation. + if (ui_immediate->isChecked() && ui_pre->isChecked()) { + packet_contents.append("1"); + } + else { + packet_contents.append("0"); } // If the server we're on supports Looping SFX and Screenshake, use it if the // emote uses it. - if (ao_app->looping_sfx_supported) { - packet_contents.append( - ao_app->get_sfx_looping(current_char, current_emote)); - packet_contents.append(QString::number(screenshake_state)); - - QString pre_emote = ao_app->get_pre_emote(current_char, current_emote); - QString emote = ao_app->get_emote(current_char, current_emote); - QStringList emotes_to_check = {pre_emote, "(b)" + emote, "(a)" + emote}; - QStringList effects_to_check = {"_FrameScreenshake", "_FrameRealization", - "_FrameSFX"}; - - foreach (QString f_effect, effects_to_check) { - QString packet; - foreach (QString f_emote, emotes_to_check) { - packet += f_emote; - if (Options::getInstance().networkedFrameSfxEnabled()) { - QString sfx_frames = - ao_app - ->read_ini_tags( - ao_app->get_character_path(current_char, "char.ini"), - f_emote.append(f_effect)) - .join("|"); - if (sfx_frames != "") - packet += "|" + sfx_frames; - } - packet += "^"; + packet_contents.append(ao_app->get_sfx_looping(current_char, current_emote)); + packet_contents.append(QString::number(screenshake_state)); + + QString pre_emote = ao_app->get_pre_emote(current_char, current_emote); + QString emote = ao_app->get_emote(current_char, current_emote); + QStringList emotes_to_check = {pre_emote, "(b)" + emote, "(a)" + emote}; + QStringList effects_to_check = {"_FrameScreenshake", "_FrameRealization", + "_FrameSFX"}; + + for (const QString &f_effect : effects_to_check) { + QString packet; + for (QString f_emote : emotes_to_check) { + packet += f_emote; + if (ao_app->is_frame_network_enabled()) { + QString sfx_frames = + ao_app + ->read_ini_tags( + ao_app->get_character_path(current_char, "char.ini"), + f_emote.append(f_effect)) + .join("|"); + if (sfx_frames != "") + packet += "|" + sfx_frames; } - packet_contents.append(packet); + packet += "^"; } + packet_contents.append(packet); } - if (ao_app->additive_text_supported) { - packet_contents.append(ui_additive->isChecked() ? "1" : "0"); - } - if (ao_app->effects_supported) { - QString p_effect_folder = + packet_contents.append(ui_additive->isChecked() ? "1" : "0"); + QString fx_sound = + ao_app->get_effect_property(effect, current_char, "sound"); + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); QString fx_sound = ao_app->get_effect_property(effect, current_char, p_effect_folder, "sound"); - // Don't overlap the two sfx - if (!ui_pre->isChecked() && (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() == 1)) { - fx_sound = "0"; - } + // Don't overlap the two sfx + if (!ui_pre->isChecked() && (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() == 1)) { + fx_sound = "0"; + } - packet_contents.append(effect + "|" + p_effect_folder + "|" + fx_sound); - if (!Options::getInstance().clearEffectsDropdownOnPlayEnabled() && !ao_app->get_effect_property(effect, current_char, p_effect_folder, "sticky").startsWith("true")) { - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); - effect = ""; - } + packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); + if (!ao_app->is_stickyeffects_enabled() && !ao_app->get_effect_property(effect, current_char, "sticky").startsWith("true")) { + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); @@ -2210,18 +2093,7 @@ void Courtroom::skip_chatmessage_queue() void Courtroom::unpack_chatmessage(QStringList p_contents) { for (int n_string = 0; n_string < MS_MAXIMUM; ++n_string) { - // Note that we have added stuff that vanilla clients and servers simply - // won't send. So now, we have to check if the thing we want even exists - // amongst the packet's content. We also have to check if the server even - // supports CCCC's IC features, or if it's just japing us. Also, don't - // forget! A size 15 message will have indices from 0 to 14. - if (n_string < p_contents.size() && - (n_string < MS_MINIMUM || ao_app->cccc_ic_supported)) { - m_chatmessage[n_string] = p_contents.at(n_string); - } - else { - m_chatmessage[n_string] = ""; - } + m_chatmessage[n_string] = p_contents.at(n_string); } // if the char ID matches our client's char ID (most likely, this is our message coming back to us) @@ -2483,72 +2355,6 @@ void Courtroom::display_character() // Determine if we should flip the character or not ui_vp_player_char->set_flipped(m_chatmessage[FLIP].toInt() == 1); - // Move the character on the viewport according to the offsets - set_self_offset(m_chatmessage[SELF_OFFSET]); -} - -void Courtroom::display_pair_character(QString other_charid, QString other_offset) -{ - // If pair information exists - if (!other_charid.isEmpty()) { - // Initialize the "ok" bool check to see if the toInt conversion succeeded - bool ok; - // Grab the charid of the pair - int charid = other_charid.split("^")[0].toInt(&ok); - // If the charid is an int and is valid... - if (ok && charid > -1) { - // Show the pair character - ui_vp_sideplayer_char->show(); - // Obtain the offsets, splitting it up by & char - QStringList offsets = other_offset.split("&"); - int offset_x; - int offset_y; - // If we only got one number... - if (offsets.length() <= 1) { - // That's just the X offset. Make Y offset 0. - offset_x = other_offset.toInt(); - offset_y = 0; - } - else { - // We got two numbers, set x and y offsets! - offset_x = offsets[0].toInt(); - offset_y = offsets[1].toInt(); - } - // Move pair character according to the offsets - ui_vp_sideplayer_char->move(ui_viewport->width() * offset_x / 100, - ui_viewport->height() * offset_y / 100); - // Split the charid according to the ^ to determine if we have "ordering" info - QStringList args = other_charid.split("^"); - if (args.size() > - 1) // This ugly workaround is so we don't make an extra packet just - // for this purpose. Rewrite pairing when? - { - // Change the order of appearance based on the pair order variable - int order = args.at(1).toInt(); - switch (order) { - case 0: // Our character is in front - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - break; - case 1: // Our character is behind - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - break; - default: - break; - } - } - // Flip the pair character - if (ao_app->flipping_supported && m_chatmessage[OTHER_FLIP].toInt() == 1) - ui_vp_sideplayer_char->set_flipped(true); - else - ui_vp_sideplayer_char->set_flipped(false); - - // Play the other pair character's idle animation - QString filename = "(a)" + m_chatmessage[OTHER_EMOTE]; - ui_vp_sideplayer_char->set_play_once(false); - ui_vp_sideplayer_char->load_image(filename, m_chatmessage[OTHER_NAME], - 0, false); - } - } } void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate) @@ -2604,24 +2410,8 @@ void Courtroom::handle_ic_message() // Update the chatbox information initialize_chatbox(); - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - bool immediate = m_chatmessage[IMMEDIATE].toInt() == 1; if (m_chatmessage[EMOTE] != "") { - // Display our own character - display_character(); - - // Reset the pair character - ui_vp_sideplayer_char->stop(); - ui_vp_sideplayer_char->move(0, 0); - - // If the emote_mod is not zooming - if (emote_mod != ZOOM && emote_mod != PREANIM_ZOOM) { - // Display the pair character - display_pair_character(m_chatmessage[OTHER_CHARID], m_chatmessage[OTHER_OFFSET]); - } - - // Parse the emote_mod part of the chat message - handle_emote_mod(emote_mod, immediate); + do_transition(m_chatmessage[DESK_MOD], last_side, m_chatmessage[SIDE]); } else { @@ -2690,6 +2480,107 @@ void Courtroom::do_screenshake() screenshake_animation_group->start(); } +void Courtroom::do_transition(QString p_desk_mod, QString old_pos, QString new_pos) { + + QPair old_pos_pair = ao_app->get_pos_path(old_pos); + QPair new_pos_pair = ao_app->get_pos_path(new_pos); + + if (old_pos == new_pos || old_pos_pair.first != new_pos_pair.first || new_pos_pair.second == -1) { + +#ifdef DEBUG_TRANSITION + qDebug() << "skipping transition - not applicable"; +#endif + post_transition_cleanup(); + return; + } +#ifdef DEBUG_TRANSITION + // for debugging animation + ui_vp_sideplayer_char->setStyleSheet("background-color:rgba(255, 0, 0, 128);"); + + qDebug() << "STARTING TRANSITION, CURRENT TIME:" << transition_animation_group->currentTime(); +#endif + + set_scene(p_desk_mod, old_pos); + + display_character(); + + const QList &affected_list = {ui_vp_background, ui_vp_desk, ui_vp_player_char}; + + int duration = ao_app->get_pos_transition_duration(old_pos, new_pos); + + // Set up the background, desk, and player objects' animations + + float scaling_factor = ui_vp_background->get_scaling_factor(); + int offset = (float(old_pos_pair.second) * scaling_factor) - (float(new_pos_pair.second) * scaling_factor); + + for (AOLayer *ui_element : affected_list) { + QPropertyAnimation *transition_animation = new QPropertyAnimation(ui_element, "pos", this); + transition_animation->setStartValue(ui_element->pos()); + transition_animation->setDuration(duration); + transition_animation->setEndValue(QPoint(ui_element->pos().x() + offset, ui_element->pos().y())); + transition_animation->setEasingCurve(QEasingCurve::InOutCubic); + transition_animation_group->addAnimation(transition_animation); + } + + // Setting up the former pair character to work for us as our stand-in for the next character + // This should be easy. But it isn't + + QString slide_emote; + if (m_chatmessage[OBJECTION_MOD].contains("4&") || m_chatmessage[OBJECTION_MOD].toInt() > 0) + slide_emote = "(a)pointing"; + else if (m_chatmessage[EMOTE_MOD].toInt() != IDLE) + slide_emote = "(a)normal"; + else + slide_emote = "(a)" + m_chatmessage[EMOTE]; + + // Load the image we're going to use to get scaling information, and move it into the final position for animation data + ui_vp_sideplayer_char->set_flipped(m_chatmessage[FLIP].toInt()); + ui_vp_sideplayer_char->load_image(slide_emote, m_chatmessage[CHAR_NAME], 0, false); + set_self_offset(m_chatmessage[SELF_OFFSET], ui_vp_sideplayer_char); + + QPoint starting_position = QPoint(ui_vp_player_char->pos().x() - offset, ui_vp_player_char->pos().y()); + QPropertyAnimation *ui_vp_sideplayer_animation = new QPropertyAnimation(ui_vp_sideplayer_char, "pos", this); + + ui_vp_sideplayer_animation->setDuration(duration); + ui_vp_sideplayer_animation->setStartValue(starting_position); + ui_vp_sideplayer_animation->setEndValue(ui_vp_sideplayer_char->pos()); + ui_vp_sideplayer_animation->setEasingCurve(QEasingCurve::InOutCubic); + transition_animation_group->addAnimation(ui_vp_sideplayer_animation); + + ui_vp_sideplayer_char->move(starting_position.x(), starting_position.y()); + ui_vp_player_char->freeze(); + ui_vp_player_char->show(); + ui_vp_sideplayer_char->freeze(); + QTimer::singleShot(TRANSITION_BOOKEND_DELAY, transition_animation_group, SLOT(start())); +} + + +void Courtroom::on_transition_finish() { + transition_animation_group->clear(); + transition_animation_group->setCurrentTime(0); + QTimer::singleShot(TRANSITION_BOOKEND_DELAY, this, SLOT(post_transition_cleanup())); +} + +void Courtroom::post_transition_cleanup() { + + set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); + + // Move the character on the viewport according to the offsets + set_self_offset(m_chatmessage[SELF_OFFSET], ui_vp_player_char); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + bool immediate = m_chatmessage[IMMEDIATE].toInt() == 1; + + + // Reset the pair character + ui_vp_sideplayer_char->stop(); + ui_vp_sideplayer_char->move_and_center(0, 0); + + // Parse the emote_mod part of the chat message + handle_emote_mod(emote_mod, immediate); + +} + void Courtroom::do_flash() { if (!Options::getInstance().effectsEnabled()) @@ -2949,6 +2840,7 @@ void Courtroom::display_evidence_image() QString f_image = local_evidence_list.at(f_evi_id - 1).image; //QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; // def jud and hlp should display the evidence icon on the RIGHT side + // TODO: Make this configured by the background bool is_left_side = !(side == "def" || side == "hlp" || side == "jud" || side == "jur"); ui_vp_evidence_display->show_evidence(f_evi_id, f_image, is_left_side, @@ -2968,6 +2860,7 @@ void Courtroom::handle_ic_speaking() // Obtain character information for our character QString filename; // I still hate this hardcoding. If we're on pos pro, hlp and wit, use prosecution_speedlines. Otherwise, defense_speedlines. + // TODO: Make this configured by the background if (side == "pro" || side == "hlp" || side == "wit") filename = "prosecution_speedlines"; else @@ -3522,7 +3415,7 @@ void Courtroom::start_chat_ticking() // handle expanded desk mods switch(m_chatmessage[DESK_MOD].toInt()) { case DESK_EMOTE_ONLY_EX: - set_self_offset(m_chatmessage[SELF_OFFSET]); + set_self_offset(m_chatmessage[SELF_OFFSET], ui_vp_player_char); [[fallthrough]]; case DESK_EMOTE_ONLY: case DESK_SHOW: @@ -3909,8 +3802,11 @@ void Courtroom::play_sfx() void Courtroom::set_scene(bool show_desk, const QString f_side) { - ui_vp_background->load_image(ao_app->get_pos_path(f_side)); - ui_vp_desk->load_image(ao_app->get_pos_path(f_side, true)); + QPair bg_pair = ao_app->get_pos_path(f_side); + QPair desk_pair = ao_app->get_pos_path(f_side, true); + ui_vp_background->load_image(bg_pair.first, bg_pair.second); + ui_vp_desk->load_image(desk_pair.first, desk_pair.second); + last_side = f_side; if (show_desk) ui_vp_desk->show(); @@ -3918,7 +3814,7 @@ void Courtroom::set_scene(bool show_desk, const QString f_side) ui_vp_desk->hide(); } -void Courtroom::set_self_offset(const QString& p_list) { +void Courtroom::set_self_offset(const QString& p_list, AOLayer* p_layer) { QStringList self_offsets = p_list.split("&"); int self_offset = self_offsets[0].toInt(); int self_offset_v; @@ -4203,18 +4099,24 @@ void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); - //We ignore it when the server is compatible with 2.8 - //Using an arbitrary 2.8 feature flag certainly won't cause issues someday. - if (ooc_message.startsWith("/pos") & !ao_app->effects_supported) { - if (ooc_message == "/pos jud") { - show_judge_controls(true); - } - else { - show_judge_controls(false); - } + // DEBUG FADE COMMANDS, REMOVE THESE B4 PROD + if (ooc_message.startsWith("/fade")) { + if (ooc_message == "/fadeout") { + ui_vp_player_char->fade(false, 700); + } + else if (ooc_message == "/fadein") { + ui_vp_player_char->fade(true, 700); + } + else if (ooc_message == "/fadebgout") { + ui_vp_void->show(); + ui_vp_background->fade(false, 700); + } + else if (ooc_message == "/fadebgin") { + ui_vp_background->fade(true, 700); + } + return; } - - if (ooc_message.startsWith("/load_case")) { + else if (ooc_message.startsWith("/load_case")) { #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); #else @@ -4905,48 +4807,6 @@ void Courtroom::on_mute_list_clicked(QModelIndex p_index) } } -void Courtroom::on_pair_list_clicked(QModelIndex p_index) -{ - QListWidgetItem *f_item = ui_pair_list->item(p_index.row()); - QString f_char = f_item->text(); - QString real_char; - int f_cid = -1; - - if (f_char.endsWith(" [x]")) { - real_char = f_char.left(f_char.size() - 4); - f_item->setText(real_char); - } - else { - real_char = f_char; - for (int n_char = 0; n_char < char_list.size(); n_char++) { - if (char_list.at(n_char).name == real_char) - f_cid = n_char; - } - } - - if (f_cid < -2 || f_cid >= char_list.size()) { - qWarning() << "" << real_char << " not present in char_list"; - return; - } - - other_charid = f_cid; - - // Redo the character list. - QStringList sorted_pair_list; - - for (const char_type &i_char : qAsConst(char_list)) - sorted_pair_list.append(i_char.name); - - sorted_pair_list.sort(); - - for (int i = 0; i < ui_pair_list->count(); i++) { - ui_pair_list->item(i)->setText(sorted_pair_list.at(i)); - } - if (other_charid != -1) { - f_item->setText(real_char + " [x]"); - } -} - void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column) { @@ -4959,12 +4819,10 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, QStringList packet_contents; packet_contents.append(p_song); packet_contents.append(QString::number(m_cid)); - if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || - ao_app->effects_supported) + if (!ui_ic_chat_name->text().isEmpty()) packet_contents.append(ui_ic_chat_name->text()); - if (ao_app->effects_supported) - packet_contents.append(QString::number(music_flags)); - ao_app->send_server_packet(new AOPacket("MC", packet_contents)); + packet_contents.append(QString::number(music_flags)); + ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) @@ -5050,11 +4908,15 @@ void Courtroom::music_random() } if (clist.length() == 0) return; +<<<<<<< HEAD + on_music_list_double_clicked(clist.at(QRandomGenerator::system()->bounded(-255, 255) % clist.length()), 1); +======= #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) on_music_list_double_clicked(clist.at(qrand() % clist.length()), 1); #else on_music_list_double_clicked(clist.at(QRandomGenerator::global()->bounded(0, clist.length())), 1); #endif +>>>>>>> 7c1fe80d4cbece55149b6fd52e3e90515f440446 } void Courtroom::music_list_expand_all() { ui_music_list->expandAll(); } @@ -5089,16 +4951,13 @@ void Courtroom::music_stop(bool no_effects) packet_contents.append( fake_song); // this is our fake song, playing it triggers special code packet_contents.append(QString::number(m_cid)); - if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || - ao_app->effects_supported) + if (!ui_ic_chat_name->text().isEmpty()) packet_contents.append(ui_ic_chat_name->text()); - if (ao_app->effects_supported) { - if (no_effects) - packet_contents.append("0"); - else - packet_contents.append(QString::number(music_flags)); - } - ao_app->send_server_packet(new AOPacket("MC", packet_contents)); + if (no_effects) + packet_contents.append("0"); + else + packet_contents.append(QString::number(music_flags)); + ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) @@ -5246,11 +5105,6 @@ void Courtroom::on_mute_clicked() { if (ui_mute_list->isHidden()) { ui_mute_list->show(); - ui_pair_list->hide(); - ui_pair_offset_spinbox->hide(); - ui_pair_vert_offset_spinbox->hide(); - ui_pair_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); ui_mute->set_image("mute_pressed"); } else { @@ -5259,32 +5113,6 @@ void Courtroom::on_mute_clicked() } } -void Courtroom::on_pair_clicked() -{ - if (ui_pair_list->isHidden()) { - ui_pair_list->show(); - ui_pair_offset_spinbox->show(); - if(ao_app->y_offset_supported) - ui_pair_vert_offset_spinbox->show(); - ui_pair_order_dropdown->show(); - ui_mute_list->hide(); - ui_mute->set_image("mute"); - ui_pair_button->set_image("pair_button_pressed"); - } - else { - ui_pair_list->hide(); - ui_pair_offset_spinbox->hide(); - ui_pair_vert_offset_spinbox->hide(); - ui_pair_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); - } -} - -void Courtroom::on_pair_order_dropdown_changed(int p_index) -{ - pair_order = p_index; -} - void Courtroom::on_defense_minus_clicked() { int f_state = defense_bar_state - 1; @@ -5549,37 +5377,31 @@ void Courtroom::on_spectator_clicked() { char_clicked(-1); } void Courtroom::on_call_mod_clicked() { - if (ao_app->modcall_reason_supported) { - QMessageBox errorBox; - QInputDialog input; + QMessageBox errorBox; + QInputDialog input; - input.setWindowFlags(Qt::WindowSystemMenuHint); - input.setLabelText(tr("Reason:")); - input.setWindowTitle(tr("Call Moderator")); - auto code = input.exec(); - - if (code != QDialog::Accepted) - return; + input.setWindowFlags(Qt::WindowSystemMenuHint); + input.setLabelText(tr("Reason:")); + input.setWindowTitle(tr("Call Moderator")); + auto code = input.exec(); - QString text = input.textValue(); - if (text.isEmpty()) { - errorBox.critical(nullptr, tr("Error"), tr("You must provide a reason.")); - return; - } - else if (text.length() > 256) { - errorBox.critical(nullptr, tr("Error"), tr("The message is too long.")); - return; - } - - QStringList mod_reason; - mod_reason.append(text); + if (code != QDialog::Accepted) + return; - ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + QString text = input.textValue(); + if (text.isEmpty()) { + errorBox.critical(nullptr, tr("Error"), tr("You must provide a reason.")); + return; } else { ao_app->send_server_packet(new AOPacket("ZZ")); } + QStringList mod_reason; + mod_reason.append(text); + + ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + ui_ic_chat_message->setFocus(); } diff --git a/src/main.cpp b/src/main.cpp index 5b696fef1..63f4cb0b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,7 +56,6 @@ int main(int argc, char *argv[]) main_app.installTranslator(&appTranslator); main_app.construct_lobby(); - main_app.net_manager->get_server_list(std::bind(&Lobby::list_servers, main_app.w_lobby)); main_app.net_manager->send_heartbeat(); main_app.w_lobby->show(); return main_app.exec(); diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp index cc1441530..55b61c9ab 100644 --- a/src/misc_functions.cpp +++ b/src/misc_functions.cpp @@ -2,8 +2,9 @@ void delay(int p_milliseconds) { - QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - - while (QTime::currentTime() < dieTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + QEventLoop loop; + QTimer t; + t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit); + t.start(p_milliseconds); + loop.exec(); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 9bd4d8f69..f4fb23a27 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -41,22 +41,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (f_contents.size() == 0) goto end; - // default(legacy) values - yellow_text_supported = false; - prezoom_supported = false; - flipping_supported = false; - custom_objection_supported = false; - desk_mod_supported = false; - evidence_supported = false; - cccc_ic_supported = false; - arup_supported = false; - casing_alerts_supported = false; - modcall_reason_supported = false; - looping_sfx_supported = false; - additive_text_supported = false; - effects_supported = false; - y_offset_supported = false; - QString f_hdid; f_hdid = get_hdid(); @@ -72,10 +56,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) client_id = f_contents.at(0).toInt(); server_software = f_contents.at(1); - net_manager->server_connected(true); - - QStringList f_contents = {"AO2", get_version_string()}; - send_server_packet(new AOPacket("ID", f_contents)); + send_server_packet(new AOPacket("ID#misairu#" + get_version_string() + "#%")); } else if (header == "CT") { if (!courtroom_constructed || f_contents.size() < 2) { @@ -89,68 +70,9 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); } - else if (header == "FL") { - yellow_text_supported = false; - prezoom_supported = false; - flipping_supported = false; - custom_objection_supported = false; - desk_mod_supported = false; - evidence_supported = false; - cccc_ic_supported = false; - arup_supported = false; - casing_alerts_supported = false; - modcall_reason_supported = false; - looping_sfx_supported = false; - additive_text_supported = false; - effects_supported = false; - expanded_desk_mods_supported = false; - auth_packet_supported = false; - if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) - yellow_text_supported = true; - if (f_packet.contains("prezoom", Qt::CaseInsensitive)) - prezoom_supported = true; - if (f_packet.contains("flipping", Qt::CaseInsensitive)) - flipping_supported = true; - if (f_packet.contains("customobjections", Qt::CaseInsensitive)) - custom_objection_supported = true; - if (f_packet.contains("deskmod", Qt::CaseInsensitive)) - desk_mod_supported = true; - if (f_packet.contains("evidence", Qt::CaseInsensitive)) - evidence_supported = true; - if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) - cccc_ic_supported = true; - if (f_packet.contains("arup", Qt::CaseInsensitive)) - arup_supported = true; - if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) - casing_alerts_supported = true; - if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) - modcall_reason_supported = true; - if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) - looping_sfx_supported = true; - if (f_packet.contains("additive", Qt::CaseInsensitive)) - additive_text_supported = true; - if (f_packet.contains("effects", Qt::CaseInsensitive)) - effects_supported = true; - if (f_packet.contains("y_offset", Qt::CaseInsensitive)) - y_offset_supported = true; - if (f_packet.contains("expanded_desk_mods", Qt::CaseInsensitive)) - expanded_desk_mods_supported = true; - if (f_packet.contains("auth_packet", Qt::CaseInsensitive)) - auth_packet_supported = true; - log_to_demo = false; - } else if (header == "PN") { if (!lobby_constructed || f_contents.size() < 2) goto end; - - w_lobby->set_player_count(f_contents.at(0).toInt(), - f_contents.at(1).toInt()); - - if (f_contents.size() >= 3) { - w_lobby->set_server_description(f_contents.at(2)); - } - - log_to_demo = false; } else if (header == "SI") { if (!lobby_constructed || f_contents.size() != 3) { @@ -174,39 +96,11 @@ void AOApplication::server_packet_received(AOPacket *p_packet) courtroom_loaded = false; - int selected_server = w_lobby->get_selected_server(); - QString server_address = "", server_name = ""; - switch (w_lobby->pageSelected()) { - case 0: - if (selected_server >= 0 && selected_server < server_list.size()) { - auto info = server_list.at(selected_server); - server_name = info.name; - server_address = - QString("%1:%2").arg(info.ip, QString::number(info.port)); - window_title = server_name; - } - break; - case 1: - { - QVector favorite_list = Options::getInstance().favorites(); - if (selected_server >= 0 && selected_server < favorite_list.size()) { - auto info = favorite_list.at(selected_server); - server_name = info.name; - server_address = - QString("%1:%2").arg(info.ip, QString::number(info.port)); - window_title = server_name; - } - } - break; - case 2: - window_title = "Local Demo Recording"; - break; - default: - break; - } + w_courtroom->set_window_title("misairu alpha - not for distribution"); - if (courtroom_constructed) - w_courtroom->set_window_title(window_title); + w_lobby->show_loading_overlay(); + w_lobby->set_loading_text(tr("Loading")); + w_lobby->set_loading_value(0); AOPacket *f_packet; @@ -577,7 +471,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } // Auth packet else if (header == "AUTH") { - if (!courtroom_constructed || !auth_packet_supported || f_contents.isEmpty()) { + if (!courtroom_constructed || f_contents.size() < 1) goto end; } bool ok; diff --git a/src/path_functions.cpp b/src/path_functions.cpp index df76383dc..f91bc9362 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -72,75 +72,37 @@ VPath AOApplication::get_default_background_path(QString p_file) return VPath("background/default/" + p_file); } -QString AOApplication::get_pos_path(const QString& pos, const bool desk) +QPair AOApplication::get_pos_path(const QString& pos, const bool desk) { // witness is default if pos is invalid + QStringList f_pos_split = pos.split(":"); + int f_center = -1; QString f_background; QString f_desk_image; - if (file_exists(get_image_suffix(get_background_path("witnessempty")))) { - f_background = "witnessempty"; - f_desk_image = "stand"; - } - else { - f_background = "wit"; - f_desk_image = "wit_overlay"; - } - if (pos == "def" && file_exists(get_image_suffix( - get_background_path("defenseempty")))) { - f_background = "defenseempty"; - f_desk_image = "defensedesk"; - } - else if (pos == "pro" && - file_exists(get_image_suffix( - get_background_path("prosecutorempty")))) { - f_background = "prosecutorempty"; - f_desk_image = "prosecutiondesk"; - } - else if (pos == "jud" && file_exists(get_image_suffix( - get_background_path("judgestand")))) { - f_background = "judgestand"; - f_desk_image = "judgedesk"; - } - else if (pos == "hld" && - file_exists(get_image_suffix( - get_background_path("helperstand")))) { - f_background = "helperstand"; - f_desk_image = "helperdesk"; - } - else if (pos == "hlp" && - file_exists(get_image_suffix( - get_background_path("prohelperstand")))) { - f_background = "prohelperstand"; - f_desk_image = "prohelperdesk"; + if (f_pos_split.size() > 1) { // We have a subposition! Grab the centering info from the design.ini, if it exists + bool bOk = false; + int subpos_center = read_design_ini(f_pos_split[0] + "/" + f_pos_split[1] + "_center", get_background_path("design.ini")).toInt(&bOk); + if (bOk) + f_center = subpos_center; } - else if (pos == "jur" && file_exists(get_image_suffix( - get_background_path("jurystand")))) { - f_background = "jurystand"; - f_desk_image = "jurydesk"; - } - else if (pos == "sea" && - file_exists(get_image_suffix( - get_background_path("seancestand")))) { - f_background = "seancestand"; - f_desk_image = "seancedesk"; - } - if (file_exists(get_image_suffix( - get_background_path(pos)))) // Unique pos path - { - f_background = pos; - f_desk_image = pos + "_overlay"; - } + get_background_path(f_pos_split[0])))) // Unique pos path + f_background = f_pos_split[0]; + else + f_background = "wit"; + + f_desk_image = f_background + "_overlay"; + QString desk_override = read_design_ini("overlays/" + f_background, get_background_path("design.ini")); if (desk_override != "") { f_desk_image = desk_override; } if (desk) { - return f_desk_image; + return {f_desk_image, f_center}; } - return f_background; + return {f_background, f_center}; } VPath AOApplication::get_evidence_path(QString p_file) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 8aba93fd1..704ccb2b9 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -843,3 +843,25 @@ bool AOApplication::get_pos_is_judge(const QString &p_pos) } return positions.contains(p_pos.trimmed()); } + +int AOApplication::get_pos_transition_duration(const QString &old_pos, const QString &new_pos) +{ + QString true_pos = old_pos.split(":")[0]; + if (old_pos.split(":").size() < 2 || new_pos.split(":").size() < 2 || (true_pos != new_pos.split(":")[0])) + return -1; + QStringList transitions = read_design_ini(true_pos + "/transitions", get_background_path("design.ini")).split(","); + + for (const QString &transition : transitions) { + QStringList transition_split = transition.split(":"); + if (transition_split.contains(old_pos.split(":")[1]) && transition_split.contains(new_pos.split(":")[1])) { + if (transition_split.size() < 3 || !transition_split[2].toInt() || transition_split[2].toInt() < 0) { + return -1; //invalid format + } + else + return transition_split[2].toInt(); + } + else + continue; + } + return -1; +} \ No newline at end of file