From fe00c6b7defe10a2c63b690c04ae2779fcccf859 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 13 Feb 2021 11:52:12 +0300 Subject: [PATCH] Animated Themes. Subthemes. Custom default_theme. Overhaul asset paths. Fix a ton of asset resolution bugs. (#466) * Remove get_static_image_suffix (webp, gif etc. can be non-animated) Replace QList with QStringList * forgot to remove static image from aoimage * Simplify get_theme_path, get_custom_theme_path and get_default_theme_path all into a single get_theme_path func Add a default_theme variable which defines the currently recognized default theme Add a new "get_asset_path" that will be used to simplify asset resolution considerably * Simplify AOImage set_image function to use get_asset_path Begin working on the subtheme system * Add p_default_theme for get_asset_path Implement get_asset_path for AOButton * Condense aolayer path lookups into the get_asset_path function * Get rid of get_font_name due to underuse (and it just does the same thing as get_design_element anyway) Get rid of get_char_shouts (use chat= instead) Use get_subtheme() instead of subtheme (because get_subtheme() can perform overrides based on the user's settings) Make get_color() use get_asset_path() Make get_design_element() use get_asset_path() * Adapt a whole bunch of text_file_functions to the get_asset_path method, fixing an enormous amount of invalid path resolutions Unfortunately I have to keep backwards compatibility for the backwards ass config.ini method for the chat markup (new way is chat_config.ini) Get rid of get_theme_effects and implement the stacking behavior into get_effects instead * Program doesn't run, color lists stop generating for some reason Also implement safety checks for the asset path generator * Fix a really tricky issue that popped up regarding char_color_rgb_list not being generated, causing segfaults * Address the sfx player path resolution being really, really stupid and resolve major inconsistencies (such as the bug where objection sfx wouldn't be playing despite the default theme or default misc folder having them) * Fix sfx path resolution being funky (apparently D:/Qt/Projects/AO2-Client/bin/base/themes/default//objection.wav is a valid qt5 path...) * Implement: get_asset_paths - Return an untested list of universal paths from the provided args get_asset_path - Loop through the list of provided asset paths and return the first valid file get_image_path - Loop through the list of provided asset paths, apply get_image_suffix and return the first valid image file get_sfx_path - Loop through the list of provided asset paths, apply get_sfx_suffix and return the first valid sound file get_asset - return an asset (must contain file extension) from the get_asset_path() applied on the get_asset_paths() get_image - return an image with get_image_suffix() applied on the get_image_path() for the get_asset_paths() get_sfx - return a sfx from provided args with the uniquely constructed asset path list for sounds Rename old get_sfx to get_court_sfx for better clarity of its function This replaces previous asset stuff I implemented, as I think this is a better solution lol * Add a new get_config_value that obtains a value from the config that matches identifier Adjust all calls to get_asset() to actually look for a config identifier value instead, so even if a config.ini is found if it doesn't contain the identifier we want we keep looking * Fix effects.ini sounds not working Remove debug text * Make it so even if you miss the required asset, and don't have a missingno, the viewport still doesn't freeze up due to waiting on Objections etc. due to signals. * Implement default_theme option for courtroom_design.ini, allowing you to make themes that inherit from other themes that are not default. * move sounds folder lower in sfx pathlist * fix realization sfx not being fetched from config * Make aosfxplayer actually use get_sfx I made Move sounds folder path check last in get_sfx * I thought this would fix QSettings::value: Empty key passed but I guess not, that annoying error will keep pestering us :((( * Remove silly .png exception for SplashLayer Fix static image Objections freezing the viewport due to done(); signal that never arrives * Make WTCE cooler by including a stop method for witness testimony indicator, and add support for custom WTCE * Reduce code duplication for get_sfx * Fix the program hanging/entering an infinite loop/segfaults/a number of nasty issues due to done(); signal being sent as soon as playback begins if the image is invalid. This is done by removing the file_exists check, and letting the rest of the functionality handle this case - the system is robust enough and treats an invalid image as a static image. * Fix segfaults with AOLayers by sanity checking using max_frames Fix "Pixmap is null" console spam * You'll hate me for this. Make it possible to have fully animated AOButton and AOImage * Add a settings option to toggle animated themes on or off * Add a setting for animated theme elements Add a "static image" toggle for get_image_suffix * Fix custom chat and generally the chat boxes not having consistent behaivor with subthemes Add a settings option for subthemes Have AOImage keep track of its last valid path * Add SubTheme (ST) packet. Pass subtheme as arg0, and "1" if you want the client's theme to be reloaded. ST packet sets ao_app->subtheme no matter what. It will not reload theme unless the user has their subtheme set to "server". Fix showname widths by rearranging font metrics to do its calculations *after* the showname font is set, and not before (making it lag behind the correct display size by 1 msg) Co-authored-by: in1tiate --- include/aoapplication.h | 48 ++++--- include/aobutton.h | 4 +- include/aoimage.h | 7 +- include/aolayer.h | 2 +- include/aooptionsdialog.h | 5 + include/courtroom.h | 2 +- src/aobutton.cpp | 54 ++++--- src/aocharbutton.cpp | 2 +- src/aoemotebutton.cpp | 2 +- src/aoevidencebutton.cpp | 2 +- src/aoevidencedisplay.cpp | 3 +- src/aoimage.cpp | 64 ++++----- src/aolayer.cpp | 101 ++++--------- src/aooptionsdialog.cpp | 69 ++++++++- src/aosfxplayer.cpp | 38 +---- src/charselect.cpp | 2 +- src/courtroom.cpp | 167 +++++++++++----------- src/lobby.cpp | 2 +- src/packet_distribution.cpp | 17 +++ src/path_functions.cpp | 127 ++++++++++++++--- src/text_file_functions.cpp | 276 ++++++++++++------------------------ 21 files changed, 514 insertions(+), 480 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index e76ad6839..9a070d469 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -130,9 +130,7 @@ class AOApplication : public QApplication { // implementation in path_functions.cpp QString get_base_path(); QString get_data_path(); - QString get_theme_path(QString p_file); - QString get_default_theme_path(QString p_file); - QString get_custom_theme_path(QString p_theme, QString p_file); + QString get_theme_path(QString p_file, QString p_theme=""); QString get_character_path(QString p_char, QString p_file); QString get_misc_path(QString p_misc, QString p_file); QString get_sounds_path(QString p_file); @@ -140,6 +138,14 @@ class AOApplication : public QApplication { QString get_background_path(QString p_file); QString get_default_background_path(QString p_file); QString get_evidence_path(QString p_file); + QStringList get_asset_paths(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder=""); + QString get_asset_path(QStringList pathlist); + QString get_image_path(QStringList pathlist, bool static_image=false); + QString get_sfx_path(QStringList pathlist); + QString get_config_value(QString p_identifier, QString p_config, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc=""); + 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=""); + QString get_sfx(QString p_sfx, QString p_misc="", QString p_character=""); QString get_case_sensitive_path(QString p_file); ////// Functions for reading and writing files ////// @@ -306,10 +312,7 @@ class AOApplication : public QApplication { // Returns the value to you QString get_design_element(QString p_identifier, QString p_file, - QString p_char = ""); - - // Returns the name of the font with p_identifier from p_file - QString get_font_name(QString p_identifier, QString p_file); + QString p_misc = ""); // Returns the value of font_size with p_identifier from p_file int get_font_size(QString p_identifier, QString p_file); @@ -323,19 +326,15 @@ class AOApplication : public QApplication { // Returns the color from the misc folder. QColor get_chat_color(QString p_identifier, QString p_chat); - // Returns the sfx with p_identifier from sounds.ini in the current theme path - QString get_sfx(QString p_identifier, QString p_misc="default"); + // Returns the sfx with p_identifier from courtroom_sounds.ini in the current theme path + QString get_court_sfx(QString p_identifier, QString p_misc=""); // Figure out if we can opus this or if we should fall back to wav QString get_sfx_suffix(QString sound_to_check); // Can we use APNG for this? If not, WEBP? If not, GIF? If not, fall back to // PNG. - QString get_image_suffix(QString path_to_check); - - // If this image is static and non-animated, return the supported static image - // formats. Currently only PNG. - QString get_static_image_suffix(QString path_to_check); + QString get_image_suffix(QString path_to_check, bool static_image=false); // Returns the value of p_search_line within target_tag and terminator_tag QString read_char_ini(QString p_char, QString p_search_line, @@ -372,9 +371,6 @@ class AOApplication : public QApplication { // Returns the value of chat font size from the specific p_char's ini file int get_chat_size(QString p_char); - // Returns the value of shouts from the specified p_char's ini file - QString get_char_shouts(QString p_char); - // Returns the preanim duration of p_char's p_emote int get_preanim_duration(QString p_char, QString p_emote); @@ -385,10 +381,6 @@ class AOApplication : public QApplication { // Not in use int get_text_delay(QString p_char, QString p_emote); - // Get the effects folder referenced by the char.ini, read it and return the - // list of filenames in a string - QStringList get_theme_effects(); - // Get the theme's effects folder, read it and return the list of filenames in // a string QStringList get_effects(QString p_char); @@ -488,6 +480,18 @@ class AOApplication : public QApplication { // Get if automatic logging is enabled bool get_auto_logging_enabled(); + // Get the subtheme from settings + QString get_subtheme(); + + // Get if the theme is animated + bool get_animated_theme(); + + // Currently defined subtheme + QString subtheme; + + QString default_theme = "default"; + QString current_theme = default_theme; + // The file name of the log file in base/logs. QString log_filename; @@ -505,8 +509,6 @@ class AOApplication : public QApplication { const int MAJOR_VERSION = 9; const int MINOR_VERSION = 0; - QString current_theme = "default"; - QVector server_list; QVector favorite_list; diff --git a/include/aobutton.h b/include/aobutton.h index f57588566..f1ae8b7fe 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -5,6 +5,7 @@ #include #include +#include class AOButton : public QPushButton { Q_OBJECT @@ -14,8 +15,9 @@ class AOButton : public QPushButton { ~AOButton(); AOApplication *ao_app; + QMovie *movie; - void set_image(QString p_image); + void set_image(QString p_image, QString p_misc=""); }; #endif // AOBUTTON_H diff --git a/include/aoimage.h b/include/aoimage.h index 01ef85400..70ff1fc0b 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -7,6 +7,7 @@ #include #include +#include class AOImage : public QLabel { public: @@ -15,9 +16,11 @@ class AOImage : public QLabel { QWidget *m_parent; AOApplication *ao_app; + QMovie *movie; - bool set_image(QString p_image); - bool set_chatbox(QString p_path); + QString path; + + bool set_image(QString p_image, QString p_misc = ""); void set_size_and_pos(QString identifier); }; diff --git a/include/aolayer.h b/include/aolayer.h index 6b4fb1f8a..c32da0248 100644 --- a/include/aolayer.h +++ b/include/aolayer.h @@ -85,7 +85,7 @@ class AOLayer : public QLabel { // 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(QList p_list); + QString find_image(QStringList p_list); protected: AOApplication *ao_app; diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index b128ce233..31f3d66db 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -45,7 +45,11 @@ class AOOptionsDialog : public QDialog { QFormLayout *ui_gameplay_form; QLabel *ui_theme_label; QComboBox *ui_theme_combobox; + QLabel *ui_subtheme_label; + QComboBox *ui_subtheme_combobox; QPushButton *ui_theme_reload_button; + QLabel *ui_animated_theme_lbl; + QCheckBox *ui_animated_theme_cb; QFrame *ui_theme_log_divider; QLabel *ui_downwards_lbl; QCheckBox *ui_downwards_cb; @@ -173,6 +177,7 @@ public slots: void discard_pressed(); void button_clicked(QAbstractButton *button); void on_reload_theme_clicked(); + void theme_changed(int i); }; #endif // AOOPTIONSDIALOG_H diff --git a/include/courtroom.h b/include/courtroom.h index 43a0910a8..eb1aa7b6a 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -505,7 +505,7 @@ class Courtroom : public QMainWindow { QVector default_color_rgb_list; // Get a color index from an arbitrary misc config - void gen_char_rgb_list(QString p_char); + void gen_char_rgb_list(QString p_misc); QVector char_color_rgb_list; // Misc we used for the last message, and the one we're using now. Used to avoid loading assets when it's not needed diff --git a/src/aobutton.cpp b/src/aobutton.cpp index b6d4af655..7f8c13fef 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -7,34 +7,42 @@ AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) { ao_app = p_ao_app; + movie = new QMovie(this); + connect(movie, &QMovie::frameChanged, [=]{ + this->setIcon(movie->currentPixmap().scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + this->setIconSize(QSize(this->width(), this->height())); + }); } AOButton::~AOButton() {} -void AOButton::set_image(QString p_image) +void AOButton::set_image(QString p_path, QString p_misc) { - QString image_path = - ao_app->get_static_image_suffix(ao_app->get_theme_path(p_image)); - QString default_image_path = - ao_app->get_static_image_suffix(ao_app->get_default_theme_path(p_image)); - - if (file_exists(image_path)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + - "\") 0 0 0 0 stretch stretch; }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); + movie->stop(); + QString p_image; + // Check if the user wants animated themes + if (ao_app->get_animated_theme()) + // We want an animated image + p_image = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc); + else + // Grab a static variant of the image + p_image = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true); + if (!file_exists(p_image)) { + this->setIcon(QIcon()); + this->setIconSize(this->size()); + this->setStyleSheet(""); + return; } - else if (file_exists(default_image_path)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + - default_image_path + - "\"); }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); + this->setText(""); + this->setStyleSheet("QPushButton { background-color: transparent; border: 0px }"); + movie->setFileName(p_image); + // We double-check if the user wants animated themes, so even if an animated image slipped through, + // we still set it static + if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + movie->start(); + } + else { + this->setIcon(QPixmap(p_image).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + this->setIconSize(this->size()); } - else - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); } diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 844c95999..3b384f35a 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -59,7 +59,7 @@ void AOCharButton::set_passworded() { ui_passworded->show(); } void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_static_image_suffix( + QString image_path = ao_app->get_image_suffix( ao_app->get_character_path(p_character, "char_icon")); this->setText(""); diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 07e6a42cb..3260a944d 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -61,7 +61,7 @@ void AOEmoteButton::set_char_image(QString p_char, int p_emote, QString suffix) { QString emotion_number = QString::number(p_emote + 1); QString image_path = - ao_app->get_static_image_suffix(ao_app->get_character_path( + ao_app->get_image_suffix(ao_app->get_character_path( p_char, "emotions/button" + emotion_number + suffix)); this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index f85a223fb..aea903add 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -58,7 +58,7 @@ void AOEvidenceButton::set_image(QString p_image) void AOEvidenceButton::set_theme_image(QString p_image) { QString theme_image_path = ao_app->get_theme_path(p_image); - QString default_image_path = ao_app->get_default_theme_path(p_image); + QString default_image_path = ao_app->get_theme_path(p_image, ao_app->default_theme); QString final_image_path; diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index f6dffd853..ef5c8fdc2 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -23,7 +23,6 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, sfx_player->set_volume(p_volume); - QString final_gif_path; QString gif_name; QString icon_identifier; @@ -50,7 +49,7 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, evidence_movie->max_duration = 1000; evidence_movie->set_play_once(true); evidence_movie->load_image(gif_name, ""); - sfx_player->play(ao_app->get_sfx("evidence_present", "default")); + sfx_player->play(ao_app->get_court_sfx("evidence_present")); } void AOEvidenceDisplay::reset() diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 3977c9792..e1bd8b8c9 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -8,49 +8,45 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { m_parent = parent; ao_app = p_ao_app; + movie = new QMovie(); + connect(movie, &QMovie::frameChanged, [=]{ + QPixmap f_pixmap = movie->currentPixmap(); + f_pixmap = + f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); + this->setPixmap(f_pixmap); + this->setMask(f_pixmap.mask()); + }); } AOImage::~AOImage() {} -bool AOImage::set_image(QString p_image) +bool AOImage::set_image(QString p_path, QString p_misc) { - QString theme_image_path = - ao_app->get_static_image_suffix(ao_app->get_theme_path(p_image)); - QString default_image_path = - ao_app->get_static_image_suffix(ao_app->get_default_theme_path(p_image)); + // Check if the user wants animated themes + if (ao_app->get_animated_theme()) + // We want an animated image + p_path = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc); + else + // Grab a static variant of the image + p_path = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true); - QString final_image_path; - - if (file_exists(theme_image_path)) - final_image_path = theme_image_path; - else if (file_exists(default_image_path)) - final_image_path = default_image_path; - else { - qDebug() << "Warning: Image" << p_image << "not found! Can't set!"; - return false; - } - - QPixmap f_pixmap(final_image_path); - f_pixmap = - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - this->setMask(f_pixmap.mask()); - return true; -} - -bool AOImage::set_chatbox(QString p_path) -{ - p_path = ao_app->get_static_image_suffix(p_path); if (!file_exists(p_path)) { - qDebug() << "Warning: Chatbox" << p_path << "not found! Can't set!"; + qDebug() << "Warning: Image" << p_path << "not found! Can't set!"; return false; } + path = p_path; + movie->stop(); + movie->setFileName(path); + if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + movie->start(); + } + else { + QPixmap f_pixmap(path); - QPixmap f_pixmap(p_path); - - f_pixmap = - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - this->setMask(f_pixmap.mask()); + f_pixmap = + f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); + this->setPixmap(f_pixmap); + this->setMask(f_pixmap.mask()); + } return true; } diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 05bec48c7..9b1ab830b 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -49,7 +49,7 @@ StickerLayer::StickerLayer(QWidget *p_parent, AOApplication *p_ao_app) { } -QString AOLayer::find_image(QList p_list) +QString AOLayer::find_image(QStringList p_list) { QString image_path; for (QString path : p_list) { @@ -75,14 +75,15 @@ QPixmap AOLayer::get_pixmap(QImage image) else f_pixmap = QPixmap::fromImage(image); // auto aspect_ratio = Qt::KeepAspectRatio; - if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; - if (stretch) - f_pixmap = f_pixmap.scaled(f_w, f_h); - else - f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); - this->resize(f_pixmap.size()); - + if (!f_pixmap.isNull()) { + if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; + if (stretch) + f_pixmap = f_pixmap.scaled(f_w, f_h); + else + f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); + this->resize(f_pixmap.size()); + } return f_pixmap; } @@ -194,7 +195,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname, << current_emote << " from character: " << p_charname << " continuous: " << continuous; #endif - QList pathlist = { + QStringList pathlist = { ao_app->get_image_suffix(ao_app->get_character_path( p_charname, prefix + current_emote)), // Default path ao_app->get_image_suffix(ao_app->get_character_path( @@ -206,42 +207,16 @@ void CharLayer::load_image(QString p_filename, QString p_charname, current_emote)), // Just use the non-prefixed image, animated or not ao_app->get_image_suffix( ao_app->get_theme_path("placeholder")), // Theme placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder"))}; // Default theme placeholder path - this->start_playback(find_image(pathlist)); + ao_app->get_image_suffix(ao_app->get_theme_path( + "placeholder", ao_app->default_theme))}; // Default theme placeholder path + start_playback(find_image(pathlist)); } void SplashLayer::load_image(QString p_filename, QString p_charname, QString p_miscname) { transform_mode = ao_app->get_misc_scaling(p_miscname); - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path( - p_charname, p_filename)), // Character folder - ao_app->get_image_suffix(ao_app->get_theme_path( - "misc/" + p_miscname + "/" + p_filename)), // Theme misc path - ao_app->get_image_suffix( - ao_app->get_misc_path(p_miscname, p_filename)), // Misc path - ao_app->get_image_suffix( - ao_app->get_theme_path(p_filename)), // Theme path - ao_app->get_image_suffix( - ao_app->get_default_theme_path(p_filename)), // Default theme path - ao_app->get_image_suffix( - ao_app->get_theme_path("placeholder")), // Placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder")), // Default placeholder path - }; - QString final_image = find_image(pathlist); - if (final_image == ao_app->get_theme_path("custom.png") || - final_image == ao_app->get_default_theme_path("custom.png") || - final_image == ao_app->get_theme_path("witnesstestimony.png") || - final_image == ao_app->get_default_theme_path("witnesstestimony.png") || - final_image == ao_app->get_theme_path("crossexamination.png") || - final_image == ao_app->get_default_theme_path("crossexamination.png")) - // stupid exceptions because themes are stupid - final_image = find_image( - {ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")), - ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder"))}); + QString final_image = ao_app->get_image(p_filename, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname, p_charname, "placeholder"); start_playback(final_image); } @@ -259,36 +234,19 @@ void EffectLayer::load_image(QString p_filename, bool p_looping) void InterfaceLayer::load_image(QString p_filename, QString p_miscname) { stretch = true; - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_theme_path( - "misc/" + p_miscname + "/" + - p_filename)), // first check our theme's misc directory - ao_app->get_image_suffix(ao_app->get_misc_path( - p_miscname, p_filename)), // then check our global misc folder - ao_app->get_image_suffix(ao_app->get_theme_path( - p_filename)), // then check the user's theme for a default image - ao_app->get_image_suffix(ao_app->get_default_theme_path( - p_filename))}; // and finally check the default theme - start_playback(find_image(pathlist)); + QString final_image = ao_app->get_image(p_filename, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname); + start_playback(final_image); } void StickerLayer::load_image(QString p_charname) { - QString miscname = ao_app->get_char_shouts(p_charname); - transform_mode = ao_app->get_misc_scaling(miscname); - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + - miscname + "/sticker/" + p_charname), // Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(miscname, "sticker/" + p_charname)), // Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path("sticker/" + p_charname)), // Theme path - ao_app->get_image_suffix( - ao_app->get_default_theme_path("sticker/" + p_charname)), // Default theme path - ao_app->get_image_suffix( - ao_app->get_character_path(p_charname, "sticker")), // Character folder - ao_app->get_image_suffix( - ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way - }; - start_playback(find_image(pathlist)); + QString p_miscname = ao_app->get_chat(p_charname); + transform_mode = ao_app->get_misc_scaling(p_miscname); + QString final_image = ao_app->get_image("sticker/" + p_charname, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname); + if (!file_exists((final_image))) + final_image = ao_app->get_image_suffix( + ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way + start_playback(final_image); } void CharLayer::start_playback(QString p_image) @@ -311,9 +269,6 @@ void AOLayer::start_playback(QString p_image) movie_frames.clear(); movie_delays.clear(); - if (!file_exists(p_image)) - return; - if (!ao_app->is_continuous_enabled()) { continuous = false; force_continuous = true; @@ -423,6 +378,8 @@ void AOLayer::set_max_duration(int p_max_duration) void CharLayer::load_effects() { movie_effects.clear(); + if (max_frames <= 1) + return; movie_effects.resize(max_frames); for (int e_frame = 0; e_frame < max_frames; ++e_frame) { QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame); @@ -445,6 +402,8 @@ void CharLayer::load_effects() void CharLayer::load_network_effects() { movie_effects.clear(); + if (max_frames <= 1) + return; movie_effects.resize(max_frames); // Order is important!!! QStringList effects_list = {"shake", "flash", "sfx^"}; @@ -525,6 +484,7 @@ void AOLayer::stop() // do we want a frozen gif to display this->freeze(); this->hide(); + shfx_timer->stop(); } void AOLayer::freeze() @@ -532,7 +492,6 @@ void AOLayer::freeze() // aT nO pOiNt Do We WaNt A fRoZeN gIf To DiSpLaY ticker->stop(); preanim_timer->stop(); - shfx_timer->stop(); } void CharLayer::movie_ticker() @@ -544,7 +503,7 @@ void CharLayer::movie_ticker() void AOLayer::movie_ticker() { ++frame; - if ((frame >= max_frames) && (max_frames > 1)) { + if (frame >= max_frames) { if (play_once) { if (cull_image) this->stop(); diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 36a6f0621..dfd8555df 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -81,17 +81,55 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_theme_combobox->addItem(actualname); } + QObject::connect(ui_theme_combobox, SIGNAL(currentIndexChanged(int)), this, + SLOT(theme_changed(int))); ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); + row += 1; + + ui_subtheme_label = new QLabel(ui_form_layout_widget); + ui_subtheme_label->setText(tr("Subtheme:")); + ui_subtheme_label->setToolTip( + tr("Sets a 'subtheme', which will stack on top of the current theme and replace anything it can." + "Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging.")); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_subtheme_label); + ui_subtheme_combobox = new QComboBox(ui_form_layout_widget); + + // Fill the combobox with the names of the themes. + ui_subtheme_combobox->addItem("server"); + ui_subtheme_combobox->addItem("default"); + QDirIterator it2(ao_app->get_base_path() + "themes/" + ao_app->current_theme, QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it2.hasNext()) { + QString actualname = QDir(it2.next()).dirName(); + if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") + ui_subtheme_combobox->addItem(actualname); + } + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_subtheme_combobox); + + row += 1; + ui_theme_reload_button = new QPushButton(ui_form_layout_widget); ui_theme_reload_button->setText(tr("Reload Theme")); ui_theme_reload_button->setToolTip( tr("Refresh the theme and update all of the ui elements to match.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_reload_button); QObject::connect(ui_theme_reload_button, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); + row += 1; + ui_animated_theme_lbl = new QLabel(ui_form_layout_widget); + ui_animated_theme_lbl->setText(tr("Animated Theme:")); + ui_animated_theme_lbl->setToolTip( + tr("If ticked, themes will be allowed to have animated elements.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_animated_theme_lbl); + + ui_animated_theme_cb = new QCheckBox(ui_form_layout_widget); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_animated_theme_cb); + row += 1; ui_theme_log_divider = new QFrame(ui_form_layout_widget); ui_theme_log_divider->setMidLineWidth(0); @@ -837,11 +875,21 @@ void AOOptionsDialog::update_values() { break; } } + QString subtheme = + ao_app->configini->value("subtheme").value(); + for (int i = 0; i < ui_subtheme_combobox->count(); ++i) { + if (ui_subtheme_combobox->itemText(i) == subtheme) + { + ui_subtheme_combobox->setCurrentIndex(i); + break; + } + } // Let's fill the callwords text edit with the already present callwords. ui_callwords_textbox->document()->clear(); foreach (QString callword, ao_app->get_call_words()) { ui_callwords_textbox->appendPlainText(callword); } + ui_animated_theme_cb->setChecked(ao_app->get_animated_theme()); ui_ms_textbox->setText(ao_app->configini->value("master", "").value()); ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); ui_username_textbox->setText(ao_app->get_default_username()); @@ -894,6 +942,8 @@ void AOOptionsDialog::save_pressed() ao_app->get_audio_output_device(); configini->setValue("theme", ui_theme_combobox->currentText()); + configini->setValue("subtheme", ui_subtheme_combobox->currentText()); + configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); configini->setValue("log_maximum", ui_length_spinbox->value()); configini->setValue("log_newline", ui_log_newline_cb->isChecked()); @@ -991,12 +1041,29 @@ void AOOptionsDialog::button_clicked(QAbstractButton *button) { void AOOptionsDialog::on_reload_theme_clicked() { ao_app->configini->setValue("theme", ui_theme_combobox->currentText()); + ao_app->configini->setValue("subtheme", ui_subtheme_combobox->currentText()); + ao_app->configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); if (ao_app->courtroom_constructed) ao_app->w_courtroom->on_reload_theme_clicked(); if (ao_app->lobby_constructed) ao_app->w_lobby->set_widgets(); } +void AOOptionsDialog::theme_changed(int i) { + ui_subtheme_combobox->clear(); + // Fill the combobox with the names of the themes. + ui_subtheme_combobox->addItem("server"); + ui_subtheme_combobox->addItem("default"); + QDirIterator it(ao_app->get_base_path() + "themes/" + ui_theme_combobox->itemText(i), QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") + ui_subtheme_combobox->addItem(actualname); + } + +} + #if (defined(_WIN32) || defined(_WIN64)) bool AOOptionsDialog::needs_default_audiodev() { return true; } #elif (defined(LINUX) || defined(__linux__)) diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 13de04fe7..000b6a7eb 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -24,7 +24,7 @@ void AOSfxPlayer::loop_clear() set_volume_internal(m_volume); } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) +void AOSfxPlayer::play(QString p_sfx, QString p_character, QString p_misc) { for (int i = 0; i < m_channelmax; ++i) { if (BASS_ChannelIsActive(m_stream_list[i]) == BASS_ACTIVE_PLAYING) @@ -34,42 +34,14 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) break; } } - - QString misc_path = ""; - QString char_path = ""; - QString theme_path = ""; - QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - - if (shout != "") { - misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + - shout + "/" + p_sfx); - theme_path = ao_app->get_sfx_suffix(ao_app->get_theme_path(p_sfx)); - if (!file_exists(theme_path)) - theme_path = - ao_app->get_sfx_suffix(ao_app->get_default_theme_path(p_sfx)); - } - if (p_char != "") - char_path = - ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); - - QString f_path; - - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else if (shout != "" && file_exists(theme_path)) // only check here for shouts - f_path = theme_path; - else - f_path = sound_path; - - if (f_path.endsWith(".opus")) + QString path = ao_app->get_sfx(p_sfx, p_misc, p_character); + if (path.endsWith(".opus")) m_stream_list[m_channel] = BASS_OPUS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, + FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); else m_stream_list[m_channel] = BASS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, + FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); set_volume_internal(m_volume); diff --git a/src/charselect.cpp b/src/charselect.cpp index bdd951c15..4f3ba991e 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -252,7 +252,7 @@ void Courtroom::character_loading_finished() // create the character tree item QTreeWidgetItem *treeItem = new QTreeWidgetItem(); treeItem->setText(0, char_list.at(n).name); - treeItem->setIcon(0, QIcon(ao_app->get_static_image_suffix( + treeItem->setIcon(0, QIcon(ao_app->get_image_suffix( ao_app->get_character_path(char_list.at(n).name, "char_icon")))); treeItem->setText(1, QString::number(n)); // category logic diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d03bf23f9..19a00c521 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -476,6 +476,9 @@ void Courtroom::set_pair_list() void Courtroom::set_widgets() { QString filename = "courtroom_design.ini"; + // Update the default theme from the courtroom_design.ini, if it's not defined it will be 'default'. + QSettings settings(ao_app->get_theme_path(filename, ao_app->current_theme), QSettings::IniFormat); + ao_app->default_theme = settings.value("default_theme", "default").toString(); pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); @@ -644,13 +647,13 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_list, "music_list"); ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); - QString music_list_indentation = ao_app->get_font_name("music_list_indent", "courtroom_design.ini"); + QString music_list_indentation = ao_app->get_design_element("music_list_indent", "courtroom_design.ini"); if (music_list_indentation == "") ui_music_list->resetIndentation(); else ui_music_list->setIndentation(music_list_indentation.toInt()); - QString music_list_animated = ao_app->get_font_name("music_list_animated", "courtroom_design.ini"); + QString music_list_animated = ao_app->get_design_element("music_list_animated", "courtroom_design.ini"); if (music_list_animated == "1") ui_music_list->setAnimated(true); else @@ -1053,12 +1056,12 @@ void Courtroom::set_font(QWidget *widget, QString class_name, QString design_file = "courtroom_fonts.ini"; if (f_pointsize <= 0) f_pointsize = - ao_app->get_design_element(p_identifier, design_file, p_char).toInt(); + ao_app->get_design_element(p_identifier, design_file, ao_app->get_chat(p_char)).toInt(); if (font_name == "") font_name = - ao_app->get_design_element(p_identifier + "_font", design_file, p_char); + ao_app->get_design_element(p_identifier + "_font", design_file, ao_app->get_chat(p_char)); QString f_color_result = - ao_app->get_design_element(p_identifier + "_color", design_file, p_char); + ao_app->get_design_element(p_identifier + "_color", design_file, ao_app->get_chat(p_char)); QColor f_color(0, 0, 0); if (f_color_result != "") { QStringList color_list = f_color_result.split(","); @@ -1070,10 +1073,10 @@ void Courtroom::set_font(QWidget *widget, QString class_name, } } bool bold = - ao_app->get_design_element(p_identifier + "_bold", design_file, p_char) == + ao_app->get_design_element(p_identifier + "_bold", design_file, ao_app->get_chat(p_char)) == "1"; // is the font bold or not? bool antialias = ao_app->get_design_element(p_identifier + "_sharp", - design_file, p_char) != + design_file, ao_app->get_chat(p_char)) != "1"; // is the font anti-aliased or not? this->set_qfont(widget, class_name, @@ -2095,7 +2098,7 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show } QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + QString f_custom_theme = ao_app->get_chat(f_char); if (objection_mod <= 4 && objection_mod >= 1) { QString shout_message; switch (objection_mod) { @@ -2215,19 +2218,19 @@ bool Courtroom::handle_objection() case 1: filename = "holdit_bubble"; objection_player->play("holdit", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 2: filename = "objection_bubble"; objection_player->play("objection", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); if (ao_app->objection_stop_music()) music_player->stop(); break; case 3: filename = "takethat_bubble"; objection_player->play("takethat", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; // case 4 is AO2 only case 4: @@ -2236,20 +2239,20 @@ bool Courtroom::handle_objection() objection_player->play( "custom_objections/" + custom_objection.split('.')[0], m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); } else { filename = "custom"; objection_player->play( "custom", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); } break; m_chatmessage[EMOTE_MOD] = 1; } ui_vp_objection->load_image( filename, m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); sfx_player->clear(); // Objection played! Cut all sfx. return true; } @@ -2490,7 +2493,7 @@ void Courtroom::do_flash() return; QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + QString f_custom_theme = ao_app->get_chat(f_char); ui_vp_effect->stretch = true; ui_vp_effect->set_static_duration(60); ui_vp_effect->set_max_duration(60); @@ -2502,7 +2505,8 @@ void Courtroom::do_flash() void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, QString p_folder) { - + if (fx_name == "") + return; QString effect = ao_app->get_effect(fx_name, p_char, p_folder); if (effect == "") return; @@ -2554,38 +2558,20 @@ void Courtroom::initialize_chatbox() QString customchar; if (ao_app->is_customchat_enabled()) customchar = m_chatmessage[CHAR_NAME]; + QString p_misc = ao_app->get_chat(customchar); if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname { - ui_vp_chatbox->set_image("chatblank"); + ui_vp_chatbox->set_image("chatblank", p_misc); } else // Aw yeah dude do some showname magic { - if (!ui_vp_chatbox->set_image("chat")) - ui_vp_chatbox->set_image("chatbox"); - - QFontMetrics fm(ui_vp_showname->font()); -// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!! -#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) - int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); -#else - int fm_width = fm.boundingRect((ui_vp_showname->text())).width(); -#endif - QString chatbox_path = ao_app->get_theme_path("chat"); - QString chatbox = ao_app->get_chat(customchar); - - if (chatbox != "" && ao_app->is_customchat_enabled()) { - chatbox_path = ao_app->get_theme_path("misc/" + chatbox + "/chat"); - if (!ui_vp_chatbox->set_chatbox(chatbox_path)) { - chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; - if (!ui_vp_chatbox->set_chatbox(chatbox_path)) - ui_vp_chatbox->set_chatbox(chatbox_path + "box"); - } - } + if (!ui_vp_chatbox->set_image("chat", p_misc)) + ui_vp_chatbox->set_image("chatbox", p_misc); // This should probably be called only if any change from the last chat // arrow was actually detected. pos_size_type design_ini_result = ao_app->get_element_dimensions( - "chat_arrow", "courtroom_design.ini", customchar); + "chat_arrow", "courtroom_design.ini", p_misc); if (design_ini_result.width < 0 || design_ini_result.height < 0) { qDebug() << "W: could not find \"chat_arrow\" in courtroom_design.ini"; ui_vp_chat_arrow->hide(); @@ -2596,16 +2582,19 @@ void Courtroom::initialize_chatbox() design_ini_result.height); } + // Remember to set the showname font before the font metrics check. + set_font(ui_vp_showname, "", "showname", customchar); + pos_size_type default_width = ao_app->get_element_dimensions( - "showname", "courtroom_design.ini", customchar); + "showname", "courtroom_design.ini", p_misc); int extra_width = ao_app ->get_design_element("showname_extra_width", "courtroom_design.ini", - customchar) + p_misc) .toInt(); QString align = ao_app ->get_design_element("showname_align", - "courtroom_design.ini", customchar) + "courtroom_design.ini", p_misc) .toLower(); if (align == "right") ui_vp_showname->setAlignment(Qt::AlignRight); @@ -2616,17 +2605,23 @@ void Courtroom::initialize_chatbox() else ui_vp_showname->setAlignment(Qt::AlignLeft); + QFontMetrics fm(ui_vp_showname->font()); +// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!! +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); +#else + int fm_width = fm.boundingRect((ui_vp_showname->text())).width(); +#endif if (extra_width > 0) { + QString current_path = ui_vp_chatbox->path.left(ui_vp_chatbox->path.lastIndexOf('.')); if (fm_width > default_width.width && - ui_vp_chatbox->set_chatbox( - chatbox_path + + ui_vp_chatbox->set_image(current_path + "med")) // This text be big. Let's do some shenanigans. { ui_vp_showname->resize(default_width.width + extra_width, ui_vp_showname->height()); if (fm_width > ui_vp_showname->width() && - ui_vp_chatbox->set_chatbox(chatbox_path + - "big")) // Biggest possible size for us. + ui_vp_chatbox->set_image(current_path + "big")) // Biggest possible size for us. { ui_vp_showname->resize( static_cast(default_width.width + (extra_width * 2)), @@ -2635,8 +2630,6 @@ void Courtroom::initialize_chatbox() } else ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); - - set_font(ui_vp_showname, "", "showname", customchar); } else { ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); @@ -2666,7 +2659,7 @@ void Courtroom::handle_callwords() // If our message contains that specific call word if (f_message.contains(word, Qt::CaseInsensitive)) { // Play the call word sfx on the modcall_player sound container - modcall_player->play(ao_app->get_sfx("word_call")); + modcall_player->play(ao_app->get_court_sfx("word_call")); // Make the window flash ao_app->alert(this); // Break the loop so we don't spam sound effects @@ -2709,7 +2702,7 @@ void Courtroom::handle_ic_speaking() filename = "prosecution_speedlines"; else filename = "defense_speedlines"; - ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } // Check if this is a talking color (white text, etc.) @@ -3214,7 +3207,6 @@ void Courtroom::preanim_done() set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); break; } - qDebug() << "preanim over, anim_state set to 1"; handle_ic_speaking(); } @@ -3281,9 +3273,9 @@ void Courtroom::start_chat_ticking() chat_tick_timer->start(0); // Display the first char right away last_misc = current_misc; - current_misc = ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]); - if (last_misc != current_misc) - gen_char_rgb_list(m_chatmessage[CHAR_NAME]); + current_misc = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + if (last_misc != current_misc || char_color_rgb_list.size() < max_colors) + gen_char_rgb_list(current_misc); QString f_blips = ao_app->get_blips(m_chatmessage[CHAR_NAME]); blip_player->set_blips(f_blips); @@ -3805,31 +3797,44 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) ui_vp_wtce->set_max_duration(wtce_max_time); // witness testimony if (p_wtce == "testimony1") { - sfx_name = "witness_testimony"; + // End testimony indicator + if (variant == 1) { + ui_vp_testimony->stop(); + return; + } + sfx_name = ao_app->get_court_sfx("witnesstestimony", bg_misc); filename = "witnesstestimony"; ui_vp_testimony->load_image("testimony", "", bg_misc); } // cross examination else if (p_wtce == "testimony2") { - sfx_name = "cross_examination"; + sfx_name = ao_app->get_court_sfx("crossexamination", bg_misc); filename = "crossexamination"; ui_vp_testimony->stop(); } - else if (p_wtce == "judgeruling") { + else { ui_vp_wtce->set_static_duration(verdict_static_time); ui_vp_wtce->set_max_duration(verdict_max_time); - if (variant == 0) { - sfx_name = "not_guilty"; - filename = "notguilty"; - ui_vp_testimony->stop(); + // Verdict? + if (p_wtce == "judgeruling") { + if (variant == 0) { + sfx_name = ao_app->get_court_sfx("notguilty", bg_misc); + filename = "notguilty"; + ui_vp_testimony->stop(); + } + else if (variant == 1) { + sfx_name = ao_app->get_court_sfx("guilty", bg_misc); + filename = "guilty"; + ui_vp_testimony->stop(); + } } - else if (variant == 1) { - sfx_name = "guilty"; - filename = "guilty"; - ui_vp_testimony->stop(); + // Completely custom WTCE + else { + sfx_name = p_wtce; + filename = p_wtce; } } - sfx_player->play(ao_app->get_sfx(sfx_name, bg_misc)); + sfx_player->play(sfx_name); ui_vp_wtce->load_image(filename, "", bg_misc); ui_vp_wtce->set_play_once(true); } @@ -3877,7 +3882,7 @@ void Courtroom::mod_called(QString p_ip) { ui_server_chatlog->append(p_ip); if (!ui_guard->isChecked()) { - modcall_player->play(ao_app->get_sfx("mod_call")); + modcall_player->play(ao_app->get_court_sfx("mod_call")); ao_app->alert(this); } } @@ -3892,7 +3897,7 @@ void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, (ao_app->get_casing_judge_enabled() && jud) || (ao_app->get_casing_juror_enabled() && jur) || (ao_app->get_casing_steno_enabled() && steno)) { - modcall_player->play(ao_app->get_sfx("case_call")); + modcall_player->play(ao_app->get_court_sfx("case_call")); ao_app->alert(this); } } @@ -4550,14 +4555,14 @@ void Courtroom::set_effects_dropdown() QString custom_path = ao_app->get_base_path() + "misc/" + p_effect + "/icons/"; QString theme_path = ao_app->get_theme_path("effects/icons/"); - QString default_path = ao_app->get_default_theme_path("effects/icons/"); + QString default_path = ao_app->get_theme_path("effects/icons/", "default"); for (int i = 0; i < ui_effects_dropdown->count(); ++i) { QString entry = ui_effects_dropdown->itemText(i); - QString iconpath = ao_app->get_static_image_suffix(custom_path + entry); + QString iconpath = ao_app->get_image_suffix(custom_path + entry); if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(theme_path + entry); + iconpath = ao_app->get_image_suffix(theme_path + entry); if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(default_path + entry); + iconpath = ao_app->get_image_suffix(default_path + entry); if (!file_exists(iconpath)) continue; } @@ -4588,7 +4593,7 @@ void Courtroom::on_effects_edit_requested() { QString p_path = ao_app->get_theme_path("effects/"); if (!dir_exists(p_path)) { - p_path = ao_app->get_default_theme_path("effects/"); + p_path = ao_app->get_theme_path("effects/", "default"); if (!dir_exists(p_path)) { return; } @@ -5091,21 +5096,21 @@ void Courtroom::set_text_color_dropdown() // config file once instead of several times for (int c = 0; c < max_colors; ++c) { QColor color = - ao_app->get_chat_color("c" + QString::number(c), current_char); + ao_app->get_chat_color("c" + QString::number(c), ao_app->get_chat(current_char)); color_rgb_list.append(color); color_markdown_start_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_start", current_char)); + "c" + QString::number(c) + "_start", ao_app->get_chat(current_char))); color_markdown_end_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_end", current_char)); + "c" + QString::number(c) + "_end", ao_app->get_chat(current_char))); color_markdown_remove_list.append( ao_app->get_chat_markup("c" + QString::number(c) + "_remove", - current_char) == "1"); + ao_app->get_chat(current_char)) == "1"); color_markdown_talking_list.append( ao_app->get_chat_markup("c" + QString::number(c) + "_talking", - current_char) != "0"); + ao_app->get_chat(current_char)) != "0"); QString color_name = ao_app->get_chat_markup( - "c" + QString::number(c) + "_name", current_char); + "c" + QString::number(c) + "_name", ao_app->get_chat(current_char)); if (color_name.isEmpty()) // Not defined { if (c > 0) @@ -5124,10 +5129,10 @@ void Courtroom::set_text_color_dropdown() } } -void Courtroom::gen_char_rgb_list(QString p_char) { +void Courtroom::gen_char_rgb_list(QString p_misc) { char_color_rgb_list.clear(); for (int c = 0; c < max_colors; ++c) { - QColor color = ao_app->get_chat_color("c" + QString::number(c), p_char); + QColor color = ao_app->get_chat_color("c" + QString::number(c), p_misc); char_color_rgb_list.append(color); } } diff --git a/src/lobby.cpp b/src/lobby.cpp index 39ddfa31e..314874e5c 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -244,7 +244,7 @@ void Lobby::set_font(QWidget *widget, QString p_identifier) int f_weight = ao_app->get_font_size(p_identifier, design_file); QString class_name = widget->metaObject()->className(); QString font_name = - ao_app->get_font_name(p_identifier + "_font", design_file); + ao_app->get_design_element(p_identifier + "_font", design_file); QFont font(font_name, f_weight); bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; if (use) { diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 53f6deb1d..1c8812019 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -663,6 +663,23 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (ping_time != -1) latency = ping_time; } + // Subtheme packet + else if (header == "ST") { + if (!courtroom_constructed) + goto end; + // Subtheme reserved as argument 0 + subtheme = f_contents.at(0); + + // Check if we have subthemes set to "server" + QString p_st = configini->value("subtheme").value(); + if (p_st.toLower() != "server") + // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. + return; + + // Reload theme request + if (f_contents.size() > 1 && f_contents.at(1) == "1") + w_courtroom->on_reload_theme_clicked(); + } end: diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 728f5a406..51073494b 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -41,24 +41,14 @@ QString AOApplication::get_base_path() QString AOApplication::get_data_path() { return get_base_path() + "data/"; } -QString AOApplication::get_default_theme_path(QString p_file) -{ - QString path = get_base_path() + "themes/default/" + p_file; - return get_case_sensitive_path(path); -} - -QString AOApplication::get_custom_theme_path(QString p_theme, QString p_file) +QString AOApplication::get_theme_path(QString p_file, QString p_theme) { + if (p_theme == "") + p_theme = current_theme; QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; return get_case_sensitive_path(path); } -QString AOApplication::get_theme_path(QString p_file) -{ - QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; - return get_case_sensitive_path(path); -} - QString AOApplication::get_character_path(QString p_char, QString p_file) { QString path = get_base_path() + "characters/" + p_char + "/" + p_file; @@ -112,18 +102,119 @@ QString AOApplication::get_evidence_path(QString p_file) return get_case_sensitive_path(path); } -QString AOApplication::get_case_sensitive_path(QString p_file) +QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) { - QFileInfo file(p_file); - QString file_basename = file.fileName(); + QStringList pathlist; + pathlist += p_element; // The path by itself + if (p_character != "") + pathlist += get_character_path(p_character, p_element); // Character folder + if (p_misc != "" && p_theme != "" && p_subtheme != "") + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme + "/" + p_subtheme); // Subtheme misc path + if (p_misc != "" && p_theme != "") + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme); // Theme misc path + if (p_theme != "" && p_subtheme != "") + pathlist += get_theme_path(p_element, p_theme + "/" + p_subtheme); // Subtheme path + if (p_misc != "") + pathlist += get_misc_path(p_misc, p_element); // Base misc path + if (p_theme != "") + pathlist += get_theme_path(p_element, p_theme); // Theme path + if (p_default_theme != "") + pathlist += get_theme_path(p_element, p_default_theme); // Default theme path + if (p_placeholder != "" && p_theme != "") + pathlist += get_theme_path(p_placeholder, p_theme); // Placeholder path + if (p_placeholder != "" && p_default_theme != "") + pathlist += get_theme_path(p_placeholder, p_default_theme); // Default placeholder path + return pathlist; +} + +QString AOApplication::get_asset_path(QStringList pathlist) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(p); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} + +QString AOApplication::get_image_path(QStringList pathlist, bool static_image) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(get_image_suffix(p, static_image)); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} + +QString AOApplication::get_sfx_path(QStringList pathlist) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(get_sfx_suffix(p)); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} +QString AOApplication::get_config_value(QString p_identifier, QString p_config, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc) +{ + QString path; +// qDebug() << "got request for" << p_identifier << "in" << p_config; + for (QString p : get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc)) { + p = get_case_sensitive_path(p); + if (file_exists(p)) { + QSettings settings(p, QSettings::IniFormat); + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) { +// qDebug() << "got" << p << "is a string list, returning" << value.toStringList().join(","); + return value.toStringList().join(","); + } + else if (!value.isNull()){ +// qDebug() << "got" << p << "is a string, returning" << value.toString(); + return value.toString(); + } + } + } + return ""; +} + +QString AOApplication::get_asset(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) +{ + return get_asset_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); +} +QString AOApplication::get_image(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) +{ + return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); +} + +QString AOApplication::get_sfx(QString p_sfx, QString p_misc, QString p_character) +{ + QStringList pathlist = get_asset_paths(p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character); + pathlist += get_sounds_path(p_sfx); // Sounds folder path + return get_sfx_path(pathlist); +} + +QString AOApplication::get_case_sensitive_path(QString p_file) +{ // no path traversal above base folder - if (!(file.absolutePath().startsWith(get_base_path()))) - return get_base_path() + file_basename; + if (!(p_file.startsWith(get_base_path()))) + return get_base_path() + p_file; #ifdef CASE_SENSITIVE_FILESYSTEM // first, check to see if it's actually there (also serves as base case for // recursion) + QFileInfo file(p_file); + QString file_basename = file.fileName(); if (exists(p_file)) return p_file; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index cc28628d5..919657cb9 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -281,9 +281,10 @@ QString AOApplication::read_design_ini(QString p_identifier, if (value.type() == QVariant::StringList) { return value.toStringList().join(","); } - else { + else if (!value.isNull()) { return value.toString(); } + return ""; } Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) @@ -295,23 +296,16 @@ Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); QPoint return_value; return_value.setX(0); return_value.setY(0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (value == "") + return return_value; - if (f_result == "") - return return_value; - } - - QStringList sub_line_elements = f_result.split(","); + QStringList sub_line_elements = value.split(","); if (sub_line_elements.size() < 2) return return_value; @@ -346,63 +340,32 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, return return_value; } QString AOApplication::get_design_element(QString p_identifier, QString p_file, - QString p_char) -{ - QStringList paths{get_theme_path("misc/" + get_chat(p_char) + "/" + - p_file), // user theme overrides base/misc - get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file, - get_theme_path(p_file), get_default_theme_path(p_file)}; - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); - if (!value.isEmpty()) - return value; - } - return ""; -} -QString AOApplication::get_font_name(QString p_identifier, QString p_file) + QString p_misc) { - QString design_ini_path = get_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - QString default_path = get_default_theme_path(p_file); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return ""; - } - return f_result; + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme, p_misc); + if (!value.isEmpty()) + return value; + return ""; } + +// tfw this function is only used for lobby and nowhere else int AOApplication::get_font_size(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return 10; - } - - return f_result.toInt(); + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); + if (!value.isEmpty()) + return value.toInt(); + return 10; } QColor AOApplication::get_color(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); QColor return_color(0, 0, 0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_color; - } + if (value.isEmpty()) + return return_color; - QStringList color_list = f_result.split(","); + QStringList color_list = value.split(","); if (color_list.size() < 3) return return_color; @@ -416,18 +379,11 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) QString AOApplication::get_stylesheet(QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - + QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); QFile design_ini; - - design_ini.setFileName(design_ini_path); - - if (!design_ini.open(QIODevice::ReadOnly)) { - design_ini.setFileName(default_path); - if (!design_ini.open(QIODevice::ReadOnly)) - return ""; - } + design_ini.setFileName(path); + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; QTextStream in(&design_ini); @@ -443,12 +399,9 @@ QString AOApplication::get_stylesheet(QString p_file) QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - + QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); QFile design_ini; - - design_ini.setFileName(design_ini_path); - + design_ini.setFileName(path); if (!design_ini.open(QIODevice::ReadOnly)) return ""; @@ -479,14 +432,19 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) { - QStringList paths{get_theme_path("misc/" + get_chat(p_chat) + "/config.ini"), - get_base_path() + "misc/" + get_chat(p_chat) + + // New Chadly method + QString value = get_config_value(p_identifier, "chat_config.ini", current_theme, get_subtheme(), default_theme, p_chat); + if (!value.isEmpty()) + return value.toLatin1(); + + // Backwards ass compatibility + QStringList backwards_paths{get_theme_path("misc/" + p_chat + "/config.ini"), + get_base_path() + "misc/" + p_chat + "/config.ini", get_base_path() + "misc/default/config.ini", get_theme_path("misc/default/config.ini")}; - - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); + for (const QString &p : backwards_paths) { + QString value = read_design_ini(p_identifier, p); if (!value.isEmpty()) { return value.toLatin1(); } @@ -514,22 +472,12 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) return return_color; } -QString AOApplication::get_sfx(QString p_identifier, QString p_misc) +QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc) { - QStringList paths{get_theme_path("misc/" + p_misc + "/courtroom_sounds.ini"), - get_misc_path(p_misc, "courtroom_sounds.ini"), - get_theme_path("courtroom_sounds.ini"), - get_default_theme_path("courtroom_sounds.ini")}; - - QString return_sfx = ""; - - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); - if (!value.isEmpty()) { - return value.toLatin1(); - } - } - return return_sfx; + QString value = get_config_value(p_identifier, "courtroom_sounds.ini", current_theme, get_subtheme(), default_theme, p_misc); + if (!value.isEmpty()) + return value.toLatin1(); + return ""; } QString AOApplication::get_sfx_suffix(QString sound_to_check) @@ -547,21 +495,20 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) return sound_to_check + ".wav"; } -QString AOApplication::get_image_suffix(QString path_to_check) +QString AOApplication::get_image_suffix(QString path_to_check, bool static_image) { if (file_exists(path_to_check)) return path_to_check; - if (file_exists(path_to_check + ".webp")) - return path_to_check + ".webp"; - if (file_exists(path_to_check + ".apng")) - return path_to_check + ".apng"; - if (file_exists(path_to_check + ".gif")) - return path_to_check + ".gif"; - return path_to_check + ".png"; -} - -QString AOApplication::get_static_image_suffix(QString path_to_check) -{ + // A better method would to actually use AOImageReader and see if these images have more than 1 frame. + // However, that might not be performant. + if (!static_image) { + if (file_exists(path_to_check + ".webp")) + return path_to_check + ".webp"; + if (file_exists(path_to_check + ".apng")) + return path_to_check + ".apng"; + if (file_exists(path_to_check + ".gif")) + return path_to_check + ".gif"; + } return path_to_check + ".png"; } @@ -574,7 +521,7 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); settings.beginGroup(target_tag); - QString value = settings.value(p_search_line).toString(); + QString value = settings.value(p_search_line).value(); settings.endGroup(); return value; } @@ -598,7 +545,7 @@ QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) settings.beginGroup(target_tag); QStringList keys = settings.allKeys(); foreach (QString key, keys) { - QString value = settings.value(key).toString(); + QString value = settings.value(key).value(); r_values << key + "=" + value; } if (!settings.group().isEmpty()) @@ -691,9 +638,6 @@ QString AOApplication::get_chat(QString p_char) if (p_char == "default") return "default"; QString f_result = read_char_ini(p_char, "chat", "Options"); - - // handling the correct order of chat is a bit complicated, we let the caller - // do it return f_result; } @@ -713,14 +657,6 @@ int AOApplication::get_chat_size(QString p_char) return f_result.toInt(); } -QString AOApplication::get_char_shouts(QString p_char) -{ - QString f_result = read_char_ini(p_char, "shouts", "Options"); - if (f_result == "") - return current_theme; // The default option is the current theme. - return f_result; -} - int AOApplication::get_preanim_duration(QString p_char, QString p_emote) { QString f_result = read_char_ini(p_char, p_emote, "Time"); @@ -854,7 +790,6 @@ QString AOApplication::get_sfx_looping(QString p_char, int p_emote) QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundL"); - qDebug() << f_result; if (f_result == "") return "0"; else @@ -903,37 +838,18 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) return f_result.toInt(); } -QStringList AOApplication::get_theme_effects() +QStringList AOApplication::get_effects(QString p_char) { - QString p_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); - + QString p_misc = read_char_ini(p_char, "effects", "Options"); + QString p_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, ""); + QString p_misc_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, p_misc); QStringList effects; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) - return effects; - } QStringList lines = read_file(p_path).split("\n"); - foreach (QString effect, lines) { - effect = effect.split("=")[0].trimmed().split("_")[0]; - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); + // Misc path different from default path, stack the new miscs on top of the defaults + if (p_misc_path != p_path) { + lines << read_file(p_misc_path).split("\n"); } - return effects; -} - -QStringList AOApplication::get_effects(QString p_char) -{ - QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - - QStringList effects = get_theme_effects(); - if (!file_exists(p_path)) - return effects; - - QStringList lines = read_file(p_path).split("\n"); foreach (QString effect, lines) { effect = effect.split("=")[0].trimmed().split("_")[0]; if (!effect.isEmpty() && !effects.contains(effect)) @@ -946,27 +862,13 @@ QStringList AOApplication::get_effects(QString p_char) QString AOApplication::get_effect(QString effect, QString p_char, QString p_folder) { - QString p_effect = p_folder; if (p_folder == "") - p_effect = read_char_ini(p_char, "effects", "Options"); - - QString p_path = - get_image_suffix(get_base_path() + "misc/" + p_effect + "/" + effect); - QString design_ini_path = - get_image_suffix(get_theme_path("effects/" + effect)); - QString default_path = - get_image_suffix(get_default_theme_path("effects/" + effect)); - - if (!file_exists(p_path)) { - p_path = design_ini_path; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) { - return ""; - } - } - } + p_folder = read_char_ini(p_char, "effects", "Options"); + + QString p_path = get_image("effects/" + effect, current_theme, get_subtheme(), default_theme, p_folder); + if (!file_exists(p_path)) + return ""; return p_path; } @@ -978,36 +880,20 @@ QString AOApplication::get_effect_property(QString fx_name, QString p_char, f_property = fx_name; else f_property = fx_name + "_" + p_property; - QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - QString design_ini_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); - - QString f_result = read_design_ini(f_property, p_path); - if (f_result == "") { - f_result = read_design_ini(f_property, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(f_property, default_path); - } - } + QString f_result = get_config_value(f_property, "effects/effects.ini", current_theme, get_subtheme(), default_theme, read_char_ini(p_char, "effects", "Options")); if (fx_name == "realization" && p_property == "sound") { f_result = get_custom_realization(p_char); } - - qDebug() << "got" << f_property << "of" << fx_name << "==" << f_result; - return f_result; } QString AOApplication::get_custom_realization(QString p_char) { QString f_result = read_char_ini(p_char, "realization", "Options"); - if (f_result == "") - return get_sfx("realization"); - else - return get_sfx_suffix(get_sounds_path(f_result)); + return get_court_sfx("realization"); + return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_blank_blip() @@ -1162,9 +1048,31 @@ QString AOApplication::get_casing_can_host_cases() .value(); return result; } + bool AOApplication::get_auto_logging_enabled() { QString result = configini->value("automatic_logging_enabled", "true").value(); return result.startsWith("true"); } + +QString AOApplication::get_subtheme() +{ + QString result = + configini->value("subtheme", "server").value(); + // Server means we want the server to decide for us + if (result == "server") + // 'subtheme' variable is affected by the server + result = subtheme; + // Default means we don't want any subthemes + else if (result == "default") + result = ""; + return result; +} + +bool AOApplication::get_animated_theme() +{ + QString result = + configini->value("animated_theme", "true").value(); + return result.startsWith("true"); +}